462 lines
14 KiB
Python
462 lines
14 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Default configuration files for MCP Browser.
|
|
|
|
Creates and manages default config directory at ~/.claude/mcp-browser/
|
|
with all necessary files including config, onboarding, patterns, etc.
|
|
"""
|
|
|
|
import os
|
|
import hashlib
|
|
from pathlib import Path
|
|
from typing import Dict, Optional
|
|
import yaml
|
|
import json
|
|
|
|
|
|
# Default configurations with their checksums
|
|
# This allows us to detect unmodified files and update them
|
|
DEFAULT_CONFIGS = {
|
|
"config.yaml": {
|
|
"checksum": "3f4e8b9c2a1d5678ef90ab12cd34567890abcdef1234567890abcdef12345678",
|
|
"content": """# MCP Browser Configuration
|
|
# This file is automatically generated and will be overwritten if unmodified
|
|
# To customize, modify any value and the file will be preserved
|
|
|
|
# Server definitions - Add your MCP servers here
|
|
servers:
|
|
# Example: Brave Search (requires BRAVE_API_KEY environment variable)
|
|
brave-search:
|
|
command: ["npx", "-y", "@modelcontextprotocol/server-brave-search"]
|
|
name: "brave-search"
|
|
description: "Brave Search API access"
|
|
env: {} # Environment variables are inherited, including BRAVE_API_KEY
|
|
|
|
# Example: Filesystem access
|
|
filesystem:
|
|
command: ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/home"]
|
|
name: "filesystem"
|
|
description: "File system access (read-only by default)"
|
|
args: ["--read-only"]
|
|
|
|
# Example: GitHub API (requires GITHUB_TOKEN)
|
|
github:
|
|
command: ["npx", "-y", "@modelcontextprotocol/server-github"]
|
|
name: "github"
|
|
description: "GitHub API access"
|
|
env: {} # Inherits GITHUB_TOKEN from environment
|
|
|
|
# Example: Memory/Notes server
|
|
memory:
|
|
command: ["npx", "-y", "@modelcontextprotocol/server-memory"]
|
|
name: "memory"
|
|
description: "Persistent memory and notes"
|
|
|
|
# Example: Postgres database (requires connection string)
|
|
# postgres:
|
|
# command: ["npx", "-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"]
|
|
# name: "postgres"
|
|
# description: "PostgreSQL database access"
|
|
|
|
# Built-in servers only mode (no external server)
|
|
builtin-only:
|
|
command: null
|
|
name: "builtin-only"
|
|
description: "Use only built-in Python servers"
|
|
|
|
# Default server to use (change to your preferred server)
|
|
default_server: "builtin-only"
|
|
|
|
# Enable sparse mode - Shows only essential tools initially
|
|
# This saves context tokens by hiding tool descriptions
|
|
sparse_mode: true
|
|
|
|
# Enable built-in servers (screen, memory, patterns, onboarding)
|
|
# These provide core functionality without external dependencies
|
|
enable_builtin_servers: true
|
|
|
|
# Debug mode - Shows detailed MCP communication
|
|
debug: false
|
|
|
|
# Connection settings
|
|
buffer_size: 65536
|
|
timeout: 30.0
|
|
|
|
# Tool filtering in sparse mode
|
|
# Only these tools are shown initially, others available via mcp_discover
|
|
sparse_tools:
|
|
- mcp_discover
|
|
- mcp_call
|
|
- onboarding
|
|
"""
|
|
},
|
|
|
|
"onboarding.md": {
|
|
"checksum": "9f8e7d6c5b4a3210fedcba9876543210abcdef1234567890abcdef12345678",
|
|
"content": """# MCP Browser - Model Context Protocol Browser
|
|
|
|
Welcome to MCP Browser! This tool provides a unified interface to interact with any MCP (Model Context Protocol) server while optimizing context usage for AI systems.
|
|
|
|
## 🚀 Quick Start
|
|
|
|
### First Time Setup
|
|
1. **Check available MCP servers:**
|
|
```bash
|
|
# List configured servers
|
|
mcp-browser --list-servers
|
|
|
|
# Test connection to a server
|
|
mcp-browser --server brave-search --test
|
|
```
|
|
|
|
2. **Set up environment variables for servers:**
|
|
```bash
|
|
# For Brave Search
|
|
export BRAVE_API_KEY="your-api-key"
|
|
|
|
# For GitHub
|
|
export GITHUB_TOKEN="your-token"
|
|
|
|
# Or source from a secrets file
|
|
source ~/.secrets/api-keys.sh
|
|
```
|
|
|
|
### Basic Usage
|
|
|
|
1. **Interactive Mode (default):**
|
|
```bash
|
|
mcp-browser
|
|
# or with a specific server
|
|
mcp-browser --server brave-search
|
|
```
|
|
|
|
2. **Available commands in interactive mode:**
|
|
- `list` - Show available tools (sparse mode)
|
|
- `discover <jsonpath>` - Discover tools using JSONPath
|
|
- `call <json>` - Execute any JSON-RPC call
|
|
- `onboard <identity>` - Get/set identity-specific instructions
|
|
- `help` - Show command help
|
|
- `exit` - Exit interactive mode
|
|
|
|
3. **Example workflows:**
|
|
```bash
|
|
# Discover all available tools
|
|
> discover $.tools[*].name
|
|
|
|
# Search the web using Brave
|
|
> call {"method": "tools/call", "params": {"name": "brave_web_search", "arguments": {"query": "MCP protocol"}}}
|
|
|
|
# Get onboarding for your project
|
|
> onboard MyProject
|
|
```
|
|
|
|
## 📊 Context Optimization Features
|
|
|
|
### Sparse Mode (Default)
|
|
- Only shows 3 essential meta-tools initially
|
|
- Use `mcp_discover` to find all available tools
|
|
- Saves significant context tokens
|
|
|
|
### Virtual Tools
|
|
1. **mcp_discover** - Discover tools using JSONPath queries
|
|
2. **mcp_call** - Execute any MCP server tool
|
|
3. **onboarding** - Identity-aware instruction management
|
|
|
|
### JSONPath Discovery Examples
|
|
```javascript
|
|
// Get all tool names
|
|
$.tools[*].name
|
|
|
|
// Find tools with "search" in name
|
|
$.tools[?(@.name =~ /search/i)].name
|
|
|
|
// Get input schemas for all tools
|
|
$.tools[*].inputSchema
|
|
|
|
// Find specific tool details
|
|
$.tools[?(@.name == 'brave_web_search')]
|
|
```
|
|
|
|
## 🛠 Available MCP Servers
|
|
|
|
### Built-in Python Servers (always available)
|
|
- **screen** - GNU screen session management
|
|
- **memory** - Persistent memory and context
|
|
- **patterns** - Auto-response patterns
|
|
- **onboarding** - Identity-specific instructions
|
|
|
|
### External Servers (configure in config.yaml)
|
|
- **brave-search** - Web search via Brave API
|
|
- **filesystem** - Local file system access
|
|
- **github** - GitHub API operations
|
|
- **postgres** - PostgreSQL database access
|
|
- **memory** - Persistent notes and memory
|
|
- **slack** - Slack workspace access
|
|
- **google-drive** - Google Drive operations
|
|
|
|
## 💡 Best Practices
|
|
|
|
1. **For AI/LLM Usage:**
|
|
- Keep sparse mode enabled
|
|
- Use `mcp_discover` to explore available tools
|
|
- Batch multiple operations when possible
|
|
- Store frequently used patterns in onboarding
|
|
|
|
2. **For Development:**
|
|
- Test with `--server builtin-only` first
|
|
- Use `--debug` to see MCP communication
|
|
- Check server logs for troubleshooting
|
|
|
|
3. **For Context Efficiency:**
|
|
- Use JSONPath to get only needed information
|
|
- Cache tool names and reuse them
|
|
- Leverage onboarding for project-specific patterns
|
|
|
|
## 🔧 Configuration
|
|
|
|
Configuration file: `~/.claude/mcp-browser/config.yaml`
|
|
|
|
Key settings:
|
|
- `default_server` - Server to use by default
|
|
- `sparse_mode` - Enable/disable sparse mode
|
|
- `enable_builtin_servers` - Use built-in Python servers
|
|
- `debug` - Show detailed debugging information
|
|
|
|
## 📝 Advanced Usage
|
|
|
|
### Server Mode (for integration)
|
|
```bash
|
|
# Run as MCP server (stdin/stdout)
|
|
mcp-browser --mode server
|
|
|
|
# With specific configuration
|
|
mcp-browser --config ~/myconfig.yaml --mode server
|
|
```
|
|
|
|
### Custom Configurations
|
|
1. Edit `~/.claude/mcp-browser/config.yaml`
|
|
2. Add your MCP servers
|
|
3. Set environment variables as needed
|
|
4. Restart mcp-browser
|
|
|
|
### Identity-Specific Onboarding
|
|
```bash
|
|
# Set instructions for a specific identity
|
|
> onboard ProjectX "You are working on ProjectX. Focus on API endpoints and testing."
|
|
|
|
# Retrieve instructions
|
|
> onboard ProjectX
|
|
```
|
|
|
|
## 🐛 Troubleshooting
|
|
|
|
1. **Server won't start:**
|
|
- Check if required environment variables are set
|
|
- Verify server command is correct
|
|
- Use `--debug` flag for detailed output
|
|
|
|
2. **Tools not appearing:**
|
|
- Ensure server is properly initialized
|
|
- Try `discover $.tools[*]` to see raw data
|
|
- Check if sparse mode is hiding tools
|
|
|
|
3. **Connection issues:**
|
|
- Verify network connectivity
|
|
- Check API keys and tokens
|
|
- Look at debug output for errors
|
|
|
|
## 📚 Learn More
|
|
|
|
- MCP Specification: https://modelcontextprotocol.io
|
|
- Available Servers: https://github.com/modelcontextprotocol/servers
|
|
- Report Issues: https://github.com/Xilope0/mcp-browser
|
|
|
|
Remember: This tool is optimized for AI context efficiency. When in doubt, use `mcp_discover` to explore!
|
|
"""
|
|
},
|
|
|
|
"patterns/system-patterns.json": {
|
|
"checksum": "1a2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef12345678",
|
|
"content": """{
|
|
"patterns": [
|
|
{
|
|
"id": "list_tools_sparse",
|
|
"pattern": ["list tools", "show tools", "what tools"],
|
|
"replacement": "__SPARSE_TOOLS__",
|
|
"description": "Show sparse tools when requested",
|
|
"type": "system"
|
|
},
|
|
{
|
|
"id": "discover_all_tools",
|
|
"pattern": ["show all tools", "list all tools", "discover tools"],
|
|
"replacement": "__DISCOVER_$.tools[*].name__",
|
|
"description": "Discover all available tool names",
|
|
"type": "system"
|
|
},
|
|
{
|
|
"id": "help_jsonpath",
|
|
"pattern": ["jsonpath help", "jsonpath examples", "how to use jsonpath"],
|
|
"replacement": "__HELP_JSONPATH__",
|
|
"description": "Show JSONPath query examples",
|
|
"type": "system"
|
|
}
|
|
]
|
|
}
|
|
"""
|
|
},
|
|
|
|
"patterns/custom-patterns.json": {
|
|
"checksum": "2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef12345678",
|
|
"content": """{
|
|
"patterns": []
|
|
}
|
|
"""
|
|
}
|
|
}
|
|
|
|
|
|
class ConfigManager:
|
|
"""Manages MCP Browser configuration directory."""
|
|
|
|
def __init__(self, config_dir: Optional[Path] = None):
|
|
"""Initialize config manager.
|
|
|
|
Args:
|
|
config_dir: Override default config directory
|
|
"""
|
|
if config_dir:
|
|
self.config_dir = Path(config_dir)
|
|
else:
|
|
self.config_dir = Path.home() / ".claude" / "mcp-browser"
|
|
|
|
def ensure_config_directory(self) -> None:
|
|
"""Ensure config directory exists with all default files."""
|
|
# Create directory structure
|
|
self.config_dir.mkdir(parents=True, exist_ok=True)
|
|
(self.config_dir / "patterns").mkdir(exist_ok=True)
|
|
(self.config_dir / "logs").mkdir(exist_ok=True)
|
|
(self.config_dir / "backups").mkdir(exist_ok=True)
|
|
|
|
# Create or update each config file
|
|
for filename, config_data in DEFAULT_CONFIGS.items():
|
|
self._ensure_config_file(filename, config_data)
|
|
|
|
def _ensure_config_file(self, filename: str, config_data: Dict[str, str]) -> None:
|
|
"""Ensure a config file exists and is up to date.
|
|
|
|
Args:
|
|
filename: Relative path to file within config dir
|
|
config_data: Dict with 'checksum' and 'content'
|
|
"""
|
|
filepath = self.config_dir / filename
|
|
|
|
# Create parent directories if needed
|
|
filepath.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Check if file exists and is unmodified
|
|
if filepath.exists():
|
|
current_checksum = self._calculate_checksum(filepath)
|
|
if current_checksum != config_data["checksum"]:
|
|
# File has been modified, don't overwrite
|
|
return
|
|
|
|
# Write default content
|
|
filepath.write_text(config_data["content"])
|
|
|
|
# Update checksum in our records
|
|
config_data["checksum"] = self._calculate_checksum(filepath)
|
|
|
|
def _calculate_checksum(self, filepath: Path) -> str:
|
|
"""Calculate SHA256 checksum of a file.
|
|
|
|
Args:
|
|
filepath: Path to file
|
|
|
|
Returns:
|
|
Hex string of checksum
|
|
"""
|
|
content = filepath.read_bytes()
|
|
return hashlib.sha256(content).hexdigest()
|
|
|
|
def get_config_path(self) -> Path:
|
|
"""Get path to main config file."""
|
|
return self.config_dir / "config.yaml"
|
|
|
|
def get_onboarding_path(self) -> Path:
|
|
"""Get path to onboarding file."""
|
|
return self.config_dir / "onboarding.md"
|
|
|
|
def get_patterns_dir(self) -> Path:
|
|
"""Get path to patterns directory."""
|
|
return self.config_dir / "patterns"
|
|
|
|
def load_config(self) -> dict:
|
|
"""Load the main configuration file.
|
|
|
|
Returns:
|
|
Configuration dictionary
|
|
"""
|
|
config_path = self.get_config_path()
|
|
if not config_path.exists():
|
|
self.ensure_config_directory()
|
|
|
|
with open(config_path, 'r') as f:
|
|
return yaml.safe_load(f)
|
|
|
|
def save_config(self, config: dict) -> None:
|
|
"""Save configuration to file.
|
|
|
|
Args:
|
|
config: Configuration dictionary
|
|
"""
|
|
config_path = self.get_config_path()
|
|
with open(config_path, 'w') as f:
|
|
yaml.dump(config, f, default_flow_style=False, sort_keys=False)
|
|
|
|
def get_onboarding_text(self, identity: Optional[str] = None) -> str:
|
|
"""Get onboarding text, optionally for specific identity.
|
|
|
|
Args:
|
|
identity: Optional identity for custom onboarding
|
|
|
|
Returns:
|
|
Onboarding text
|
|
"""
|
|
onboarding_path = self.get_onboarding_path()
|
|
if not onboarding_path.exists():
|
|
self.ensure_config_directory()
|
|
|
|
base_text = onboarding_path.read_text()
|
|
|
|
# Check for identity-specific onboarding
|
|
if identity:
|
|
identity_file = self.config_dir / f"onboarding-{identity}.md"
|
|
if identity_file.exists():
|
|
return identity_file.read_text()
|
|
|
|
return base_text
|
|
|
|
def set_onboarding_text(self, text: str, identity: Optional[str] = None) -> None:
|
|
"""Set onboarding text.
|
|
|
|
Args:
|
|
text: Onboarding text to save
|
|
identity: Optional identity for custom onboarding
|
|
"""
|
|
if identity:
|
|
identity_file = self.config_dir / f"onboarding-{identity}.md"
|
|
identity_file.write_text(text)
|
|
else:
|
|
self.get_onboarding_path().write_text(text)
|
|
|
|
|
|
# Update checksums with actual values
|
|
def update_checksums():
|
|
"""Update the checksums in DEFAULT_CONFIGS with actual calculated values."""
|
|
for filename, config_data in DEFAULT_CONFIGS.items():
|
|
content_bytes = config_data["content"].encode('utf-8')
|
|
config_data["checksum"] = hashlib.sha256(content_bytes).hexdigest()
|
|
|
|
|
|
# Initialize checksums
|
|
update_checksums() |