diff --git a/deployment/mcp-only/.env.example b/deployment/mcp-only/.env.example deleted file mode 100644 index 2ba1c50..0000000 --- a/deployment/mcp-only/.env.example +++ /dev/null @@ -1,48 +0,0 @@ -# Claude OS MCP-Only Deployment Configuration - -# ====================== -# Database Configuration -# ====================== -SQLITE_DB_PATH=/app/data/claude-os.db - -# ====================== -# MCP Server Configuration -# ====================== -MCP_SERVER_HOST=0.0.0.0 -MCP_SERVER_PORT=8051 - -# ====================== -# Ollama Configuration -# ====================== -OLLAMA_HOST=http://ollama:11434 -OLLAMA_EMBED_MODEL=nomic-embed-text -OLLAMA_MODEL=llama3.1:latest - -# ====================== -# CORS Configuration -# ====================== -# Comma-separated list of allowed origins -# Use "*" for development, specific domains for production -CORS_ORIGINS=* - -# ====================== -# Authentication (Optional) -# ====================== -# Uncomment to enable JWT authentication -# JWT_SECRET_KEY=your-super-secret-key-change-this-in-production -# JWT_ALGORITHM=HS256 -# API_USERNAME=admin -# API_PASSWORD=changeme - -# ====================== -# RAG Configuration -# ====================== -CHUNK_SIZE=512 -CHUNK_OVERLAP=128 -TOP_K_RETRIEVAL=20 -SIMILARITY_TOP_K=20 - -# ====================== -# Logging -# ====================== -LOG_LEVEL=INFO diff --git a/deployment/mcp-only/DEPLOYMENT_COMPARISON.md b/deployment/mcp-only/DEPLOYMENT_COMPARISON.md deleted file mode 100644 index 454face..0000000 --- a/deployment/mcp-only/DEPLOYMENT_COMPARISON.md +++ /dev/null @@ -1,382 +0,0 @@ -# Deployment Options: Your Server vs Cloudflare Workers - -You have two main options for deploying your MCP server. Here's a detailed comparison to help you choose. - -## Option 1: Docker on Your Server (This Repo) - -### What It Is -- Run the MCP server as a Docker container on your own server -- Sits alongside your other applications -- Uses your existing SQLite database directly - -### Pros ✅ - -1. **Dead Simple Setup** - - Your database is already there - - Just mount it as a volume - - No data migration needed - -2. **Zero Code Changes** - - Use the exact Python code from Claude OS - - No rewriting required - - Full feature parity - -3. **Fast Local Access** - - Your other apps can access via `http://mcp-server:8051` - - No network latency - - Can use Docker networks - -4. **Full Control** - - Choose your own models (Ollama) - - Adjust configuration freely - - Access to all RAG features (hybrid, rerank, agentic) - -5. **Cost** - - Free (you're already paying for the server) - - No additional services needed - -6. **Debugging** - - Direct access to logs - - Can inspect database - - Easy to troubleshoot - -### Cons ❌ - -1. **Server Requirements** - - Needs ~500MB disk space - - ~200-500MB RAM - - Must manage Docker containers - -2. **Scaling** - - Limited to your server's resources - - Need load balancer for multiple instances - -3. **Availability** - - Single point of failure - - Need to manage uptime yourself - -### When to Choose This - -✅ **Use Docker on your server if:** -- Your apps are already on that server -- You want the simplest setup -- You have a single server or small deployment -- You want to use your existing database directly -- You need all RAG features (hybrid search, reranking) -- You don't need global distribution - -### Example Architecture - -``` -┌──────────────────────────────────┐ -│ Your Server │ -│ │ -│ ┌──────────┐ ┌──────────┐ │ -│ │ Chat App │───▶│MCP Server│ │ -│ └──────────┘ └─────┬────┘ │ -│ │ │ -│ ┌──────────┐ │ │ -│ │ Docs App │─────────┤ │ -│ └──────────┘ │ │ -│ ▼ │ -│ ┌──────────┐ │ -│ │SQLite DB │ │ -│ └──────────┘ │ -│ │ -└──────────────────────────────────┘ -``` - ---- - -## Option 2: Cloudflare Workers (Like cloudflare_mcp) - -### What It Is -- Serverless functions running on Cloudflare's edge network -- JavaScript/TypeScript only -- Uses Cloudflare D1 (SQLite) and Vectorize (vectors) - -### How It Works - -1. **Export your SQLite data to Cloudflare D1** - ```bash - # Export schema and data - sqlite3 data/claude-os.db .dump > dump.sql - - # Import to D1 - wrangler d1 execute claude-os-db --file=dump.sql - ``` - -2. **Rewrite MCP endpoints in JavaScript** - - Translate Python → TypeScript - - Use Cloudflare APIs instead of SQLiteManager - - Use Cloudflare AI for embeddings - -3. **Deploy to Workers** - ```bash - wrangler deploy - ``` - -### Pros ✅ - -1. **Global Distribution** - - Runs in 300+ cities worldwide - - Ultra-low latency for users anywhere - - Automatic geo-routing - -2. **Auto-Scaling** - - Handles 0 to millions of requests - - No capacity planning - - Pay per use - -3. **High Availability** - - Built-in redundancy - - 100% uptime SLA (on paid plans) - - No maintenance windows - -4. **No Server Management** - - Completely serverless - - Automatic updates - - No Docker, no VMs - -5. **Free Tier** - - 100,000 requests/day free - - 10GB D1 storage free - - Good for most use cases - -### Cons ❌ - -1. **Major Rewrite Required** - - Must port Python → JavaScript/TypeScript - - Reimplement all RAG logic - - Could take days/weeks - -2. **Cloudflare Limitations** - - D1: 500MB database limit (free tier) - - Workers: 10ms CPU time per request (free tier) - - Must use Cloudflare AI models (different from Ollama) - -3. **Data Migration** - - Must export SQLite → D1 - - Must export vectors → Vectorize - - Complex migration process - -4. **Limited RAG Features** - - Cloudflare AI has fewer models - - Harder to implement advanced features - - No LlamaIndex integration - -5. **Debugging** - - Harder to debug serverless - - Limited logging (on free tier) - - Can't inspect database easily - -6. **Vendor Lock-in** - - Tied to Cloudflare ecosystem - - Migration away is difficult - -### When to Choose This - -✅ **Use Cloudflare Workers if:** -- Your apps are distributed globally -- You need extreme scalability -- You want zero server management -- You're comfortable rewriting in JavaScript -- Your database is < 500MB (or you can split it) -- You don't need advanced RAG features - -### Example Architecture - -``` - Global Users - │ - ▼ - ┌───────────────────────┐ - │ Cloudflare Edge │ - │ (300+ locations) │ - │ │ - │ ┌─────────────────┐ │ - │ │ MCP Worker │ │ - │ │ (TypeScript) │ │ - │ └────┬────────────┘ │ - │ │ │ - │ ├──▶ D1 (SQLite)│ - │ └──▶ Vectorize │ - │ │ - └───────────────────────┘ - ▲ - │ - Your Chat/Docs Apps -``` - ---- - -## Side-by-Side Comparison - -| Feature | Your Server (Docker) | Cloudflare Workers | -|---------|---------------------|-------------------| -| **Setup Time** | 5 minutes | Days (rewrite code) | -| **Code Changes** | None | Full rewrite | -| **Data Migration** | None | Complex | -| **Server Management** | Yes | No | -| **Scaling** | Manual | Automatic | -| **Global Latency** | Higher | Ultra-low | -| **Cost (small)** | $0 (existing server) | $0 (free tier) | -| **Cost (large)** | Fixed | Pay-per-use | -| **Database Size** | Unlimited | 500MB (free tier) | -| **RAG Features** | Full | Limited | -| **Model Choice** | Any (Ollama) | Cloudflare AI only | -| **Debugging** | Easy | Harder | -| **Vendor Lock-in** | None | Cloudflare | - ---- - -## Recommended Approach - -### For Your Use Case - -Based on what you described: -- ✅ You have MCPs populated with data locally -- ✅ You have other apps that need this data -- ✅ One needs it as a knowledge base -- ✅ Another needs it for live chat - -**I recommend: Start with Docker on your server (Option 1)** - -### Why? - -1. **Fastest to deploy** - 5 minutes vs days -2. **No code changes** - Use existing Python code -3. **No data migration** - Mount your existing DB -4. **Full features** - All RAG capabilities work -5. **Same server** - Your apps can access locally - -### Migration Path (If Needed Later) - -``` -Phase 1: Docker on your server (NOW) - ↓ - Get your apps working - Test performance - Measure traffic - ↓ -Phase 2: Evaluate needs (LATER) - ↓ - If scaling is needed → Consider Cloudflare - If working well → Stay with Docker -``` - ---- - -## Quick Start: Docker on Your Server - -```bash -# 1. Navigate to deployment directory -cd deployment/mcp-only/ - -# 2. Run setup script -./setup.sh - -# 3. Done! MCP server is running at http://localhost:8051 - -# 4. Update your apps to use: -# http://mcp-server:8051 (if on same Docker network) -# http://localhost:8051 (if on same server) -``` - ---- - -## Hybrid Approach (Best of Both Worlds) - -You can also do both: - -``` -┌────────────────────────────────┐ -│ Your Server (Primary) │ -│ ┌────────┐ ┌────────────┐ │ -│ │Chat App│───▶│MCP (Docker)│ │ -│ └────────┘ └────────────┘ │ -│ ┌────────┐ ▲ │ -│ │Docs App│──────────┘ │ -│ └────────┘ │ -└────────────────────────────────┘ - │ - │ (Optional: Sync to Cloudflare) - ▼ -┌────────────────────────────────┐ -│ Cloudflare (Secondary) │ -│ ┌──────────────────────────┐ │ -│ │ Read-only MCP (Workers) │ │ -│ │ For public docs search │ │ -│ └──────────────────────────┘ │ -└────────────────────────────────┘ -``` - -**Use Docker for:** -- Internal apps (chat, docs) -- Write operations -- Full RAG features - -**Use Cloudflare for:** -- Public-facing documentation search -- Global users -- Read-only queries - ---- - -## Example: Cloudflare Workers Code (If You Choose That Path) - -See the `cloudflare-workers/` directory for a basic example of how to implement the MCP endpoints on Cloudflare Workers. - -**Note:** This is a simplified example. A full implementation would require: -- Complete D1 database migration -- Vector embeddings in Vectorize -- All 12 MCP tools reimplemented -- Proper error handling and auth -- Testing and deployment - ---- - -## Decision Flowchart - -``` -Do you need global distribution? -├─ No → Use Docker on your server ✅ -│ -└─ Yes - │ - Are your apps < 100k requests/day? - ├─ Yes - │ │ - │ Is your database < 500MB? - │ ├─ Yes → Consider Cloudflare Workers - │ └─ No → Use Docker on your server ✅ - │ - └─ No → Use Docker + CDN or multiple regions -``` - ---- - -## My Recommendation - -**Start with Docker on your server.** It's: -- ✅ 10x faster to set up -- ✅ No code changes -- ✅ Uses your existing data -- ✅ Full feature set -- ✅ Easy to debug - -Then, **if you need global scaling**, consider: -1. Adding a CDN in front of your Docker deployment -2. Deploying Docker containers in multiple regions -3. Only then consider Cloudflare Workers (requires significant effort) - -Most applications don't need Cloudflare-level scaling. Your Docker deployment will likely handle thousands of requests per second, which is probably more than enough. - ---- - -## Questions? - -See: -- `README.md` - Full Docker setup guide -- `examples/` - Integration examples -- `cloudflare-workers/` - Cloudflare Workers starter (if you choose that path) diff --git a/deployment/mcp-only/Dockerfile b/deployment/mcp-only/Dockerfile deleted file mode 100644 index 16105cf..0000000 --- a/deployment/mcp-only/Dockerfile +++ /dev/null @@ -1,53 +0,0 @@ -FROM python:3.11-slim as builder - -# Install system dependencies for building -RUN apt-get update && apt-get install -y \ - gcc \ - g++ \ - make \ - libmagic1 \ - && rm -rf /var/lib/apt/lists/* - -# Create virtual environment -RUN python -m venv /opt/venv -ENV PATH="/opt/venv/bin:$PATH" - -# Copy requirements and install Python dependencies -COPY requirements.txt /tmp/ -RUN pip install --no-cache-dir -r /tmp/requirements.txt - -# Final stage -FROM python:3.11-slim - -# Install runtime dependencies -RUN apt-get update && apt-get install -y \ - libmagic1 \ - curl \ - && rm -rf /var/lib/apt/lists/* - -# Copy virtual environment from builder -COPY --from=builder /opt/venv /opt/venv -ENV PATH="/opt/venv/bin:$PATH" - -# Set working directory -WORKDIR /app - -# Copy only necessary application files -COPY mcp_server/ /app/mcp_server/ -COPY app/core/ /app/app/core/ -COPY app/db/ /app/app/db/ -COPY app/utils/ /app/app/utils/ -COPY app/__init__.py /app/app/__init__.py - -# Create data directory for database -RUN mkdir -p /app/data - -# Expose MCP server port -EXPOSE 8051 - -# Health check -HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ - CMD curl -f http://localhost:8051/health || exit 1 - -# Run MCP server -CMD ["python", "-m", "uvicorn", "mcp_server.server:app", "--host", "0.0.0.0", "--port", "8051"] diff --git a/deployment/mcp-only/README.md b/deployment/mcp-only/README.md deleted file mode 100644 index f1047e2..0000000 --- a/deployment/mcp-only/README.md +++ /dev/null @@ -1,460 +0,0 @@ -# Claude OS - MCP-Only Deployment - -This deployment package extracts **just the MCP knowledge base server** from Claude OS, allowing you to expose your populated knowledge bases to other applications without running the full coding environment. - -## 🎯 What This Does - -- ✅ Exposes MCP HTTP endpoints for knowledge base queries -- ✅ Serves your existing SQLite database (read-only by default) -- ✅ Provides RAG (Retrieval Augmented Generation) search -- ✅ Lightweight: No CLI, no coding tools, no UI -- ✅ Perfect for: Knowledge base APIs, live chat backends, documentation search - -## 🏗️ Architecture - -``` -┌─────────────────┐ -│ Your Other Apps│ -│ (Chat, Docs) │ -└────────┬────────┘ - │ HTTP/JSON-RPC - ↓ -┌─────────────────┐ -│ MCP Server │ -│ (Port 8051) │ -└────────┬────────┘ - │ - ├──→ SQLite DB (your local data/claude-os.db) - └──→ Ollama (embeddings + LLM) -``` - -## 📦 What's Included - -- **MCP Server**: HTTP endpoints for all knowledge base operations -- **SQLite Manager**: Database access layer -- **RAG Engine**: Semantic search with hybrid modes -- **Ollama**: Local AI for embeddings and LLM (required) - -## 🚀 Quick Start - -### Option 1: Using Your Existing Local Database (Recommended) - -This is the easiest approach - just mount your existing `data/claude-os.db`: - -```bash -# From the deployment/mcp-only directory -docker-compose up -d - -# This will: -# 1. Start Ollama container -# 2. Start MCP server with your DB mounted at ../../data (read-only) -# 3. Pull required models on first run -``` - -Your MCP server will be available at: `http://localhost:8051` - -### Option 2: Copy Database to Server - -If you're deploying to a remote server: - -```bash -# 1. Copy your local database to the server -scp ../../data/claude-os.db user@server:/path/to/claude-os/data/ - -# 2. On the server, start services -docker-compose up -d -``` - -### Option 3: Volume-Based (For Persistent Changes) - -If you want the Docker container to have its own copy: - -```bash -# 1. Edit docker-compose.yml - uncomment the mcp_data volume -# 2. Copy your database into the volume -docker-compose up -d -docker cp ../../data/claude-os.db claude-os-mcp:/app/data/ -``` - -## 🔧 Configuration - -### Environment Variables - -Edit `docker-compose.yml` to configure: - -```yaml -environment: - # Database (required) - SQLITE_DB_PATH: /app/data/claude-os.db - - # Ollama (required) - OLLAMA_HOST: http://ollama:11434 - OLLAMA_EMBED_MODEL: nomic-embed-text - OLLAMA_MODEL: llama3.1:latest - - # CORS - Important for your other apps! - CORS_ORIGINS: "https://your-chat-app.com,https://your-docs-app.com" - - # Optional: Authentication - JWT_SECRET_KEY: your-secret-key-here - API_USERNAME: admin - API_PASSWORD: changeme -``` - -### First-Time Setup: Pull Ollama Models - -On first run, you need to download the models: - -```bash -# Wait for containers to start -docker-compose up -d - -# Pull embedding model (required) -docker exec claude-os-ollama ollama pull nomic-embed-text - -# Pull LLM model (optional, for agentic queries) -docker exec claude-os-ollama ollama pull llama3.1:latest -``` - -## 🔌 Using the MCP Endpoints - -### Health Check - -```bash -curl http://localhost:8051/health -``` - -### List All Knowledge Bases - -```bash -curl -X POST http://localhost:8051/mcp \ - -H "Content-Type: application/json" \ - -d '{ - "jsonrpc": "2.0", - "method": "tools/call", - "params": { - "name": "list_knowledge_bases", - "arguments": {} - }, - "id": 1 - }' -``` - -### Search Knowledge Base - -```bash -curl -X POST http://localhost:8051/mcp \ - -H "Content-Type: application/json" \ - -d '{ - "jsonrpc": "2.0", - "method": "tools/call", - "params": { - "name": "search_knowledge_base", - "arguments": { - "kb_name": "my-docs", - "query": "How do I configure authentication?", - "top_k": 10 - } - }, - "id": 1 - }' -``` - -### KB-Specific Endpoint (Cleaner URLs) - -```bash -# Search a specific KB directly -curl -X POST http://localhost:8051/mcp/kb/my-docs \ - -H "Content-Type: application/json" \ - -d '{ - "jsonrpc": "2.0", - "method": "tools/call", - "params": { - "name": "search", - "arguments": { - "query": "authentication setup", - "top_k": 5 - } - }, - "id": 1 - }' -``` - -## 🔗 Integration Examples - -### Python Client - -```python -import requests - -def search_knowledge(kb_name: str, query: str, top_k: int = 10): - response = requests.post( - "http://localhost:8051/mcp", - json={ - "jsonrpc": "2.0", - "method": "tools/call", - "params": { - "name": "search_knowledge_base", - "arguments": { - "kb_name": kb_name, - "query": query, - "top_k": top_k - } - }, - "id": 1 - } - ) - return response.json()["result"] - -# Use in your chat app -results = search_knowledge("my-docs", "How to deploy?") -print(results) -``` - -### JavaScript/Node.js Client - -```javascript -async function searchKnowledge(kbName, query, topK = 10) { - const response = await fetch('http://localhost:8051/mcp', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - jsonrpc: '2.0', - method: 'tools/call', - params: { - name: 'search_knowledge_base', - arguments: { kb_name: kbName, query, top_k: topK } - }, - id: 1 - }) - }); - - const data = await response.json(); - return data.result; -} - -// Use in your app -const results = await searchKnowledge('my-docs', 'How to deploy?'); -console.log(results); -``` - -## 📊 Available MCP Tools - -### Global Endpoint (`/mcp`) - -| Tool | Description | -|------|-------------| -| `search_knowledge_base` | Semantic search across any KB | -| `list_knowledge_bases` | List all available KBs | -| `list_knowledge_bases_by_type` | Filter KBs by type | -| `create_knowledge_base` | Create new KB (if writable) | -| `get_kb_stats` | Get KB statistics | -| `list_documents` | List documents in KB | -| `ingest_agent_os_profile` | Import Agent OS data | -| `get_agent_os_stats` | Agent OS statistics | -| `get_standards` | Retrieve standards | -| `get_workflows` | Retrieve workflows | -| `get_specs` | Retrieve specifications | -| `get_product_context` | Get product context | - -### KB-Specific Endpoint (`/mcp/kb/{kb_slug}`) - -| Tool | Description | -|------|-------------| -| `search` | Search within specific KB | -| `get_stats` | Get stats for specific KB | -| `list_documents` | List documents in KB | - -## 🔒 Security Considerations - -### 1. Read-Only Database (Default) - -The default `docker-compose.yml` mounts your database as **read-only** (`:ro` flag). This prevents the container from modifying your local data. - -To allow writes (e.g., for creating new KBs), change: -```yaml -volumes: - - ../../data:/app/data:ro # Read-only -``` -to: -```yaml -volumes: - - ../../data:/app/data # Read-write -``` - -### 2. Enable Authentication - -Uncomment and set these in `docker-compose.yml`: - -```yaml -JWT_SECRET_KEY: "your-strong-secret-key-here" -API_USERNAME: "admin" -API_PASSWORD: "secure-password-here" -``` - -Then authenticate: - -```bash -# Get token -curl -X POST http://localhost:8051/token \ - -H "Content-Type: application/x-www-form-urlencoded" \ - -d "username=admin&password=secure-password-here" - -# Use token in requests -curl -X POST http://localhost:8051/mcp \ - -H "Authorization: Bearer YOUR_TOKEN" \ - -H "Content-Type: application/json" \ - -d '...' -``` - -### 3. CORS Configuration - -Restrict `CORS_ORIGINS` to your specific domains: - -```yaml -CORS_ORIGINS: "https://chat.yourapp.com,https://docs.yourapp.com" -``` - -### 4. Network Isolation - -If deploying with your other apps, use Docker networks: - -```yaml -networks: - - your_app_network -``` - -## 🌐 Cloudflare Workers Deployment - -For a serverless approach similar to [cloudflare_mcp](https://github.com/forayconsulting/cloudflare_mcp): - -### What You'd Need - -1. **Export your SQLite DB to Cloudflare D1** (their SQLite service) -2. **Rewrite MCP endpoints as Workers** (JavaScript/TypeScript) -3. **Use Cloudflare AI** instead of Ollama (for embeddings) - -### Pros of Cloudflare Approach -- ✅ Globally distributed -- ✅ Auto-scaling -- ✅ No server management - -### Cons -- ❌ Must rewrite Python → JavaScript -- ❌ Cloudflare AI models (less flexibility) -- ❌ D1 has size limits (500MB free tier) -- ❌ More complex to set up initially - -**This Docker approach** is simpler if you just need to expose your existing data to your apps on a server you control. - -## 📈 Monitoring - -### View Logs - -```bash -# MCP Server logs -docker-compose logs -f mcp-server - -# Ollama logs -docker-compose logs -f ollama -``` - -### Check Health - -```bash -# MCP Server -curl http://localhost:8051/health - -# Ollama -curl http://localhost:11434/api/tags -``` - -## 🛠️ Troubleshooting - -### Models Not Found - -```bash -# Pull models manually -docker exec claude-os-ollama ollama pull nomic-embed-text -docker exec claude-os-ollama ollama pull llama3.1:latest -``` - -### Database Not Found - -```bash -# Verify database path -docker exec claude-os-mcp ls -la /app/data/ - -# Check if mounted correctly -docker inspect claude-os-mcp | grep -A 10 Mounts -``` - -### CORS Errors - -Update `CORS_ORIGINS` in `docker-compose.yml` to include your app's domain. - -### Port Conflicts - -If port 8051 or 11434 are in use, change them: - -```yaml -ports: - - "9051:8051" # Use port 9051 externally -``` - -## 🔄 Updating Your Database - -### While Container is Running - -Your database is mounted from `../../data/claude-os.db`. Any changes you make locally (using Claude OS) will be immediately visible to the container. - -```bash -# No restart needed - changes are live! -# Just query the MCP endpoint and you'll see new data -``` - -### Deploying to Production - -1. **Option A: Sync database periodically** - ```bash - # Cron job to sync from local to server - rsync -avz data/claude-os.db user@server:/path/to/data/ - ``` - -2. **Option B: Use shared network storage** - - Mount same NFS/S3 volume on both local and server - -3. **Option C: Use database replication** - - Set up SQLite replication (more complex) - -## 📚 Next Steps - -1. **Deploy this to your server** alongside your other apps -2. **Update CORS** to allow your chat/docs apps -3. **Enable authentication** for production -4. **Configure monitoring** (logs, health checks) -5. **Set up database sync** if needed - -## 🆚 Comparison: This vs. Full Claude OS - -| Feature | MCP-Only | Full Claude OS | -|---------|----------|----------------| -| Knowledge Base API | ✅ | ✅ | -| CLI Coding Assistant | ❌ | ✅ | -| Frontend UI | ❌ | ✅ | -| File Watchers | ❌ | ✅ | -| Spec Tracking | ❌ | ✅ | -| Project Management | ❌ | ✅ | -| Container Size | ~500MB | ~2GB | -| Memory Usage | ~200MB | ~1GB | - -## 📞 Support - -For issues specific to: -- **MCP Endpoints**: See `/docs/API_REFERENCE.md` in main repo -- **Deployment**: Open issue in claude-os repo -- **Your Apps Integration**: This is the right approach! - -## 🎉 You're All Set! - -Your knowledge bases are now available as an API for your other applications to consume. No coding environment needed - just pure data access! diff --git a/deployment/mcp-only/cloudflare-workers/README.md b/deployment/mcp-only/cloudflare-workers/README.md deleted file mode 100644 index ff19fe9..0000000 --- a/deployment/mcp-only/cloudflare-workers/README.md +++ /dev/null @@ -1,328 +0,0 @@ -# Cloudflare Workers Deployment (Alternative Approach) - -This directory contains a **starter template** for deploying Claude OS MCP endpoints on Cloudflare Workers, similar to the [cloudflare_mcp](https://github.com/forayconsulting/cloudflare_mcp) project. - -> ⚠️ **Important**: This is a **significant undertaking** compared to the Docker approach. Only use this if you need global distribution and auto-scaling. - -## What This Requires - -### 1. Cloudflare Account Setup -- Cloudflare account (free tier available) -- D1 database (Cloudflare's SQLite service) -- Vectorize (Cloudflare's vector search service) -- Workers AI (for embeddings) - -### 2. Code Rewrite -- Rewrite all Python code → JavaScript/TypeScript -- Reimplement SQLiteManager → D1 queries -- Reimplement RAGEngine → Vectorize queries -- Port all 12 MCP tools - -### 3. Data Migration -- Export SQLite schema and data -- Import to D1 -- Extract vectors and import to Vectorize -- Set up sync process (if needed) - -## Estimated Effort - -| Task | Time Estimate | -|------|--------------| -| Setup Cloudflare infrastructure | 2-4 hours | -| Migrate database schema | 1-2 hours | -| Migrate data and vectors | 2-4 hours | -| Rewrite MCP endpoints | 8-16 hours | -| Testing and debugging | 4-8 hours | -| **Total** | **17-34 hours** | - -Compare to Docker approach: **5 minutes** - -## When to Use This - -✅ Only use Cloudflare Workers if: -- You have **global users** across continents -- You need **automatic scaling** beyond a single server -- You're okay with **vendor lock-in** to Cloudflare -- You have **time to rewrite** the codebase in JavaScript -- Your database is **< 500MB** (free tier limit) - -Otherwise, use the Docker approach. - -## Quick Start - -### 1. Install Wrangler (Cloudflare CLI) - -```bash -npm install -g wrangler - -# Login to Cloudflare -wrangler login -``` - -### 2. Create D1 Database - -```bash -# Create database -wrangler d1 create claude-os-db - -# This will output a database ID - save it! -``` - -### 3. Export Your SQLite Database - -```bash -# From the root of claude-os repo -sqlite3 data/claude-os.db .dump > deployment/mcp-only/cloudflare-workers/schema.sql -``` - -### 4. Import to D1 - -```bash -cd deployment/mcp-only/cloudflare-workers - -# Import schema and data -wrangler d1 execute claude-os-db --file=schema.sql -``` - -### 5. Create Vectorize Index - -```bash -# Create vector index (for embeddings) -wrangler vectorize create claude-os-vectors --dimensions=768 --metric=cosine - -# Note: You'll need to export and import your vectors separately -``` - -### 6. Configure wrangler.toml - -Edit `wrangler.toml` with your database and vectorize IDs: - -```toml -name = "claude-os-mcp" -main = "src/index.ts" -compatibility_date = "2024-01-01" - -[[d1_databases]] -binding = "DB" -database_name = "claude-os-db" -database_id = "your-database-id-here" - -[[vectorize]] -binding = "VECTORIZE" -index_name = "claude-os-vectors" -index_id = "your-vectorize-id-here" - -[ai] -binding = "AI" -``` - -### 7. Implement MCP Endpoints - -See `src/index.ts` for a basic example. You'll need to implement all tools: - -```typescript -// Example structure -export default { - async fetch(request: Request, env: Env): Promise { - const { pathname } = new URL(request.url); - - // Health check - if (pathname === '/health') { - return new Response(JSON.stringify({ status: 'ok' })); - } - - // MCP endpoint - if (pathname === '/mcp') { - const body = await request.json(); - const result = await handleMCPRequest(body, env); - return new Response(JSON.stringify(result)); - } - - return new Response('Not found', { status: 404 }); - } -}; -``` - -### 8. Deploy - -```bash -wrangler deploy -``` - -Your MCP server will be available at: `https://claude-os-mcp.your-subdomain.workers.dev` - -## Code Structure - -``` -cloudflare-workers/ -├── src/ -│ ├── index.ts # Main worker entry point -│ ├── handlers/ -│ │ ├── search.ts # Search knowledge base -│ │ ├── list.ts # List KBs -│ │ └── ... # Other tools -│ ├── db/ -│ │ ├── queries.ts # D1 query helpers -│ │ └── schema.ts # Type definitions -│ └── utils/ -│ ├── embeddings.ts # Workers AI embeddings -│ └── vectorize.ts # Vectorize queries -├── wrangler.toml # Cloudflare config -├── package.json -├── tsconfig.json -└── schema.sql # Exported database -``` - -## Key Differences from Python Version - -### Database Access - -**Python (SQLiteManager):** -```python -def query_documents(kb_name, query_embedding, n_results): - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute("SELECT ... FROM documents WHERE ...") - return cursor.fetchall() -``` - -**TypeScript (D1):** -```typescript -async function queryDocuments(env: Env, kbName: string, n: number) { - const results = await env.DB.prepare( - "SELECT ... FROM documents WHERE ..." - ).all(); - return results; -} -``` - -### Vector Search - -**Python (sqlite-vec):** -```python -cursor.execute(""" - SELECT *, vec_distance_cosine(embedding, ?) as distance - FROM documents - ORDER BY distance - LIMIT ? -""", [query_embedding, n_results]) -``` - -**TypeScript (Vectorize):** -```typescript -const matches = await env.VECTORIZE.query(queryEmbedding, { - topK: n, - returnMetadata: true -}); -``` - -### Embeddings - -**Python (Ollama):** -```python -from llama_index.embeddings.ollama import OllamaEmbedding - -embedding_model = OllamaEmbedding( - model_name="nomic-embed-text", - base_url="http://localhost:11434" -) -embedding = embedding_model.get_query_embedding(text) -``` - -**TypeScript (Workers AI):** -```typescript -const embedding = await env.AI.run('@cf/baai/bge-base-en-v1.5', { - text: queryText -}); -``` - -## Migration Script Example - -Here's a script to export your vectors for Vectorize: - -```python -# export_vectors.py -import sqlite3 -import json - -conn = sqlite3.connect('../../data/claude-os.db') -cursor = conn.cursor() - -cursor.execute(""" - SELECT id, embedding, metadata - FROM documents -""") - -vectors = [] -for doc_id, embedding, metadata in cursor.fetchall(): - vectors.append({ - 'id': str(doc_id), - 'values': list(embedding), # Convert BLOB to list - 'metadata': json.loads(metadata) - }) - -with open('vectors.json', 'w') as f: - json.dump(vectors, f) -``` - -Then import to Vectorize: -```bash -# You'll need to use the Vectorize API -# See: https://developers.cloudflare.com/vectorize/ -``` - -## Limitations - -### Free Tier -- D1: 5 GB storage, 5M rows read/day, 100K writes/day -- Vectorize: 30M queries/month, 10M dimensions stored -- Workers: 100K requests/day, 10ms CPU per request - -### Paid Tier Required For -- Large databases (> 500MB) -- High query volume (> 100K/day) -- Long-running queries (> 10ms CPU) - -## Testing Locally - -```bash -# Install dependencies -npm install - -# Run local dev server -wrangler dev - -# Test endpoint -curl http://localhost:8787/health -``` - -## Comparison with Docker Approach - -| Feature | Docker | Cloudflare Workers | -|---------|--------|-------------------| -| Setup time | 5 min | 17-34 hours | -| Code changes | None | Complete rewrite | -| Database | Direct use | Must migrate | -| Scaling | Manual | Automatic | -| Cost (small) | $0 | $0 | -| Cost (large) | Fixed | Variable | -| Latency | Regional | Global | - -## My Recommendation - -**Unless you have specific requirements for global distribution, use the Docker approach.** - -The Cloudflare Workers approach is powerful but requires significant development effort. It's best suited for: -- Public-facing APIs with global users -- Applications that need to scale to millions of requests -- Teams with JavaScript/TypeScript expertise - -For most use cases, Docker on your server is simpler, faster, and more maintainable. - -## Resources - -- [Cloudflare Workers Docs](https://developers.cloudflare.com/workers/) -- [D1 Database Docs](https://developers.cloudflare.com/d1/) -- [Vectorize Docs](https://developers.cloudflare.com/vectorize/) -- [Workers AI Docs](https://developers.cloudflare.com/workers-ai/) -- [Example: cloudflare_mcp](https://github.com/forayconsulting/cloudflare_mcp) diff --git a/deployment/mcp-only/cloudflare-workers/package.json b/deployment/mcp-only/cloudflare-workers/package.json deleted file mode 100644 index 30502c5..0000000 --- a/deployment/mcp-only/cloudflare-workers/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "claude-os-mcp-cloudflare", - "version": "1.0.0", - "description": "Claude OS MCP Server on Cloudflare Workers", - "main": "src/index.ts", - "scripts": { - "dev": "wrangler dev", - "deploy": "wrangler deploy", - "tail": "wrangler tail", - "d1:create": "wrangler d1 create claude-os-db", - "d1:import": "wrangler d1 execute claude-os-db --file=schema.sql", - "vectorize:create": "wrangler vectorize create claude-os-vectors --dimensions=768 --metric=cosine" - }, - "keywords": [ - "mcp", - "knowledge-base", - "rag", - "cloudflare", - "workers" - ], - "author": "", - "license": "MIT", - "devDependencies": { - "@cloudflare/workers-types": "^4.20240129.0", - "typescript": "^5.3.3", - "wrangler": "^3.22.0" - } -} diff --git a/deployment/mcp-only/cloudflare-workers/src/index.ts b/deployment/mcp-only/cloudflare-workers/src/index.ts deleted file mode 100644 index 3c5a9dd..0000000 --- a/deployment/mcp-only/cloudflare-workers/src/index.ts +++ /dev/null @@ -1,303 +0,0 @@ -/** - * Claude OS MCP Server - Cloudflare Workers Implementation - * - * This is a BASIC EXAMPLE showing how to implement MCP endpoints - * on Cloudflare Workers. A production implementation would require - * all 12 tools and proper error handling. - */ - -export interface Env { - DB: D1Database; // D1 database binding - VECTORIZE: VectorizeIndex; // Vectorize binding - AI: any; // Workers AI binding -} - -interface MCPRequest { - jsonrpc: string; - method: string; - params?: { - name?: string; - arguments?: any; - }; - id: number; -} - -interface MCPResponse { - jsonrpc: string; - result?: any; - error?: { - code: number; - message: string; - }; - id: number; -} - -export default { - async fetch(request: Request, env: Env): Promise { - const url = new URL(request.url); - - // CORS headers - const corsHeaders = { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization', - }; - - // Handle preflight - if (request.method === 'OPTIONS') { - return new Response(null, { headers: corsHeaders }); - } - - // Health check - if (url.pathname === '/health') { - return new Response( - JSON.stringify({ status: 'ok', version: '1.0.0' }), - { - headers: { ...corsHeaders, 'Content-Type': 'application/json' } - } - ); - } - - // MCP endpoint - if (url.pathname === '/mcp' && request.method === 'POST') { - try { - const body: MCPRequest = await request.json(); - const response = await handleMCPRequest(body, env); - - return new Response(JSON.stringify(response), { - headers: { ...corsHeaders, 'Content-Type': 'application/json' } - }); - } catch (error) { - return new Response( - JSON.stringify({ - jsonrpc: '2.0', - error: { - code: -32603, - message: error instanceof Error ? error.message : 'Internal error' - }, - id: null - }), - { - status: 500, - headers: { ...corsHeaders, 'Content-Type': 'application/json' } - } - ); - } - } - - return new Response('Not found', { status: 404, headers: corsHeaders }); - }, -}; - -/** - * Handle MCP JSON-RPC requests - */ -async function handleMCPRequest(request: MCPRequest, env: Env): Promise { - const { method, params, id } = request; - - // Initialize method - if (method === 'initialize') { - return { - jsonrpc: '2.0', - result: { - protocolVersion: '2024-11-05', - serverInfo: { - name: 'claude-os-mcp', - version: '1.0.0' - }, - capabilities: { - tools: {} - } - }, - id - }; - } - - // List available tools - if (method === 'tools/list') { - return { - jsonrpc: '2.0', - result: { - tools: [ - { - name: 'search_knowledge_base', - description: 'Search a knowledge base for relevant information', - inputSchema: { - type: 'object', - properties: { - kb_name: { type: 'string' }, - query: { type: 'string' }, - top_k: { type: 'number' } - }, - required: ['kb_name', 'query'] - } - }, - { - name: 'list_knowledge_bases', - description: 'List all available knowledge bases', - inputSchema: { - type: 'object', - properties: {} - } - } - // TODO: Add remaining 10 tools - ] - }, - id - }; - } - - // Call a tool - if (method === 'tools/call') { - const toolName = params?.name; - const args = params?.arguments || {}; - - let result; - - switch (toolName) { - case 'search_knowledge_base': - result = await searchKnowledgeBase(env, args); - break; - - case 'list_knowledge_bases': - result = await listKnowledgeBases(env); - break; - - // TODO: Implement remaining tools: - // - list_knowledge_bases_by_type - // - create_knowledge_base - // - get_kb_stats - // - list_documents - // - ingest_agent_os_profile - // - get_agent_os_stats - // - get_standards - // - get_workflows - // - get_specs - // - get_product_context - - default: - return { - jsonrpc: '2.0', - error: { - code: -32601, - message: `Unknown tool: ${toolName}` - }, - id - }; - } - - return { - jsonrpc: '2.0', - result, - id - }; - } - - return { - jsonrpc: '2.0', - error: { - code: -32601, - message: `Unknown method: ${method}` - }, - id - }; -} - -/** - * Search knowledge base using vector similarity - */ -async function searchKnowledgeBase( - env: Env, - args: { kb_name: string; query: string; top_k?: number } -): Promise { - const { kb_name, query, top_k = 10 } = args; - - // 1. Get KB ID - const kb = await env.DB.prepare( - 'SELECT id, slug FROM knowledge_bases WHERE name = ? OR slug = ?' - ).bind(kb_name, kb_name).first(); - - if (!kb) { - throw new Error(`Knowledge base not found: ${kb_name}`); - } - - // 2. Generate query embedding using Workers AI - const embeddingResponse: any = await env.AI.run('@cf/baai/bge-base-en-v1.5', { - text: query - }); - - const queryEmbedding = embeddingResponse.data[0]; - - // 3. Search vectors using Vectorize - const matches = await env.VECTORIZE.query(queryEmbedding, { - topK: top_k, - returnMetadata: true, - filter: { kb_id: kb.id } // Filter by knowledge base - }); - - // 4. Fetch full document content from D1 - const documentIds = matches.matches.map(m => m.id); - - if (documentIds.length === 0) { - return { - results: [], - kb_name, - query, - count: 0 - }; - } - - const placeholders = documentIds.map(() => '?').join(','); - const documents = await env.DB.prepare( - `SELECT id, content, metadata FROM documents WHERE id IN (${placeholders})` - ).bind(...documentIds).all(); - - // 5. Combine results - const results = matches.matches.map((match, idx) => { - const doc = documents.results.find(d => d.id === match.id); - - return { - text: doc?.content || '', - metadata: doc?.metadata ? JSON.parse(doc.metadata) : {}, - score: match.score, - distance: 1 - match.score - }; - }); - - return { - results, - kb_name, - query, - count: results.length, - search_mode: 'vector' - }; -} - -/** - * List all knowledge bases - */ -async function listKnowledgeBases(env: Env): Promise { - const result = await env.DB.prepare( - 'SELECT id, name, slug, kb_type, description, created_at FROM knowledge_bases ORDER BY created_at DESC' - ).all(); - - return { - knowledge_bases: result.results.map(kb => ({ - id: kb.id, - name: kb.name, - slug: kb.slug, - kb_type: kb.kb_type, - description: kb.description, - created_at: kb.created_at - })), - count: result.results.length - }; -} - -/** - * Additional helper functions would go here: - * - getKBStats() - * - listDocuments() - * - createKnowledgeBase() - * - etc. - */ diff --git a/deployment/mcp-only/cloudflare-workers/tsconfig.json b/deployment/mcp-only/cloudflare-workers/tsconfig.json deleted file mode 100644 index 9070052..0000000 --- a/deployment/mcp-only/cloudflare-workers/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2021", - "lib": ["ES2021"], - "module": "ES2022", - "moduleResolution": "node", - "types": ["@cloudflare/workers-types"], - "resolveJsonModule": true, - "allowJs": true, - "checkJs": false, - "jsx": "react", - "incremental": true, - "esModuleInterop": true, - "isolatedModules": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "forceConsistentCasingInFileNames": true, - "allowSyntheticDefaultImports": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/deployment/mcp-only/cloudflare-workers/wrangler.toml b/deployment/mcp-only/cloudflare-workers/wrangler.toml deleted file mode 100644 index d99894a..0000000 --- a/deployment/mcp-only/cloudflare-workers/wrangler.toml +++ /dev/null @@ -1,23 +0,0 @@ -name = "claude-os-mcp" -main = "src/index.ts" -compatibility_date = "2024-01-01" - -# D1 Database (SQLite) -[[d1_databases]] -binding = "DB" -database_name = "claude-os-db" -database_id = "your-database-id-here" # Get this from: wrangler d1 create claude-os-db - -# Vectorize (Vector Search) -[[vectorize]] -binding = "VECTORIZE" -index_name = "claude-os-vectors" -index_id = "your-vectorize-id-here" # Get this from: wrangler vectorize create - -# Workers AI (Embeddings & LLM) -[ai] -binding = "AI" - -# Environment variables -[vars] -MCP_VERSION = "1.0.0" diff --git a/deployment/mcp-only/docker-compose.yml b/deployment/mcp-only/docker-compose.yml deleted file mode 100644 index 7bb991a..0000000 --- a/deployment/mcp-only/docker-compose.yml +++ /dev/null @@ -1,69 +0,0 @@ -version: '3.8' - -services: - # Ollama service (required for embeddings & LLM) - ollama: - image: ollama/ollama:latest - container_name: claude-os-ollama - ports: - - "11434:11434" - volumes: - - ollama_data:/root/.ollama - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"] - interval: 30s - timeout: 10s - retries: 3 - restart: unless-stopped - - # MCP Server (knowledge base access only) - mcp-server: - build: - context: ../.. # Build from root of claude-os - dockerfile: deployment/mcp-only/Dockerfile - container_name: claude-os-mcp - ports: - - "8051:8051" - volumes: - # Mount your existing database from local machine - - ../../data:/app/data:ro # Read-only: your populated DB - # Or use a volume if you want to persist changes - # - mcp_data:/app/data - environment: - # Database - SQLITE_DB_PATH: /app/data/claude-os.db - - # MCP Server - MCP_SERVER_HOST: 0.0.0.0 - MCP_SERVER_PORT: 8051 - - # Ollama connection - OLLAMA_HOST: http://ollama:11434 - OLLAMA_EMBED_MODEL: nomic-embed-text - OLLAMA_MODEL: llama3.1:latest - - # Optional: Authentication - # JWT_SECRET_KEY: your-secret-key-here - # JWT_ALGORITHM: HS256 - # API_USERNAME: admin - # API_PASSWORD: changeme - - # Optional: CORS (adjust for your other apps) - CORS_ORIGINS: "*" - - depends_on: - ollama: - condition: service_healthy - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8051/health"] - interval: 30s - timeout: 10s - retries: 3 - restart: unless-stopped - -volumes: - ollama_data: - driver: local - # Uncomment if you want persistent MCP data in Docker - # mcp_data: - # driver: local diff --git a/deployment/mcp-only/examples/chat-integration.js b/deployment/mcp-only/examples/chat-integration.js deleted file mode 100644 index 16a1aa5..0000000 --- a/deployment/mcp-only/examples/chat-integration.js +++ /dev/null @@ -1,290 +0,0 @@ -/** - * Example: Integrating Claude OS MCP with a Node.js/Express Chat Application - * - * This example shows how to use the MCP server as a knowledge base - * backend for a chat API. - */ - -const express = require('express'); -const axios = require('axios'); - -class ClaudeOSKnowledgeBase { - constructor(baseUrl = 'http://localhost:8051', apiToken = null) { - this.baseUrl = baseUrl; - this.headers = { 'Content-Type': 'application/json' }; - - if (apiToken) { - this.headers['Authorization'] = `Bearer ${apiToken}`; - } - } - - /** - * Make a JSON-RPC call to the MCP server - */ - async callTool(toolName, arguments, kbSlug = null) { - // Use KB-specific endpoint if slug provided - let url = `${this.baseUrl}/mcp`; - if (kbSlug) { - url = `${this.baseUrl}/mcp/kb/${kbSlug}`; - } - - const payload = { - jsonrpc: '2.0', - method: 'tools/call', - params: { - name: toolName, - arguments: arguments - }, - id: 1 - }; - - try { - const response = await axios.post(url, payload, { - headers: this.headers - }); - - if (response.data.error) { - throw new Error(`MCP Error: ${JSON.stringify(response.data.error)}`); - } - - return response.data.result || {}; - } catch (error) { - throw new Error(`Failed to call MCP: ${error.message}`); - } - } - - /** - * Search a knowledge base for relevant information - */ - async search(kbName, query, options = {}) { - const { - topK = 10, - useHybrid = false, - useRerank = false - } = options; - - const result = await this.callTool('search_knowledge_base', { - kb_name: kbName, - query: query, - top_k: topK, - use_hybrid: useHybrid, - use_rerank: useRerank - }); - - return result.results || []; - } - - /** - * List all available knowledge bases - */ - async listKnowledgeBases() { - const result = await this.callTool('list_knowledge_bases', {}); - return result.knowledge_bases || []; - } - - /** - * Get statistics for a knowledge base - */ - async getKBStats(kbName) { - return await this.callTool('get_kb_stats', { kb_name: kbName }); - } -} - -/** - * Create an Express.js API for the chat application - */ -function createChatAPI() { - const app = express(); - app.use(express.json()); - - // Initialize MCP client - const mcp = new ClaudeOSKnowledgeBase( - process.env.MCP_BASE_URL || 'http://localhost:8051', - process.env.MCP_API_TOKEN || null - ); - - /** - * POST /api/chat - * Ask a question and get a knowledge-based response - */ - app.post('/api/chat', async (req, res) => { - try { - const { question, kb_name, options = {} } = req.body; - - if (!question || !kb_name) { - return res.status(400).json({ - error: 'Missing required fields: question and kb_name' - }); - } - - // Search the knowledge base - const results = await mcp.search(kb_name, question, { - topK: options.top_k || 5, - useHybrid: options.use_hybrid !== false, // default true - useRerank: options.use_rerank !== false // default true - }); - - if (results.length === 0) { - return res.json({ - answer: "I couldn't find any relevant information in the knowledge base.", - sources: [] - }); - } - - // Format the context - const sources = results.map((result, idx) => ({ - id: idx + 1, - text: result.text, - filename: result.metadata?.filename || 'Unknown', - score: result.score || 0 - })); - - // In a real app, you'd call your LLM here with the context - // For this example, just return the sources - res.json({ - answer: `Found ${results.length} relevant results. (In production, this would be processed by an LLM to generate a natural language answer)`, - sources: sources, - question: question - }); - - } catch (error) { - console.error('Chat error:', error); - res.status(500).json({ - error: error.message - }); - } - }); - - /** - * GET /api/knowledge-bases - * List all available knowledge bases - */ - app.get('/api/knowledge-bases', async (req, res) => { - try { - const kbs = await mcp.listKnowledgeBases(); - - res.json({ - knowledge_bases: kbs.map(kb => ({ - name: kb.name, - slug: kb.slug, - type: kb.kb_type, - description: kb.description - })) - }); - - } catch (error) { - console.error('Error listing KBs:', error); - res.status(500).json({ - error: error.message - }); - } - }); - - /** - * GET /api/knowledge-bases/:name/stats - * Get statistics for a specific knowledge base - */ - app.get('/api/knowledge-bases/:name/stats', async (req, res) => { - try { - const stats = await mcp.getKBStats(req.params.name); - res.json(stats); - } catch (error) { - console.error('Error getting stats:', error); - res.status(500).json({ - error: error.message - }); - } - }); - - /** - * GET /health - * Health check endpoint - */ - app.get('/health', async (req, res) => { - try { - // Try to list KBs to verify MCP connection - await mcp.listKnowledgeBases(); - res.json({ status: 'ok', mcp_connected: true }); - } catch (error) { - res.status(503).json({ - status: 'degraded', - mcp_connected: false, - error: error.message - }); - } - }); - - return app; -} - -/** - * Example usage with streaming responses (for real-time chat) - */ -async function streamingChatExample(kbName, question) { - const mcp = new ClaudeOSKnowledgeBase('http://localhost:8051'); - - // 1. Search the knowledge base - const results = await mcp.search(kbName, question, { - topK: 5, - useHybrid: true, - useRerank: true - }); - - // 2. Build context for LLM - const context = results - .map((r, idx) => `[${idx + 1}] ${r.text}`) - .join('\n\n---\n\n'); - - console.log('Context for LLM:'); - console.log(context); - - // 3. In a real app, stream the LLM response - // using OpenAI SDK, Anthropic SDK, etc. - /* - const stream = await openai.chat.completions.create({ - model: 'gpt-4', - messages: [ - { - role: 'system', - content: `You are a helpful assistant. Answer the user's question based on the following context:\n\n${context}` - }, - { - role: 'user', - content: question - } - ], - stream: true - }); - - for await (const chunk of stream) { - process.stdout.write(chunk.choices[0]?.delta?.content || ''); - } - */ -} - -// Run the server if this file is executed directly -if (require.main === module) { - const app = createChatAPI(); - const PORT = process.env.PORT || 3000; - - app.listen(PORT, () => { - console.log(`Chat API server running on port ${PORT}`); - console.log(''); - console.log('Endpoints:'); - console.log(` POST http://localhost:${PORT}/api/chat`); - console.log(` GET http://localhost:${PORT}/api/knowledge-bases`); - console.log(` GET http://localhost:${PORT}/api/knowledge-bases/:name/stats`); - console.log(` GET http://localhost:${PORT}/health`); - console.log(''); - console.log('Example request:'); - console.log(` curl -X POST http://localhost:${PORT}/api/chat \\`); - console.log(` -H "Content-Type: application/json" \\`); - console.log(` -d '{"question": "How do I configure auth?", "kb_name": "my-docs"}'`); - }); -} - -module.exports = { - ClaudeOSKnowledgeBase, - createChatAPI, - streamingChatExample -}; diff --git a/deployment/mcp-only/examples/chat-integration.py b/deployment/mcp-only/examples/chat-integration.py deleted file mode 100644 index 7ea1c20..0000000 --- a/deployment/mcp-only/examples/chat-integration.py +++ /dev/null @@ -1,226 +0,0 @@ -""" -Example: Integrating Claude OS MCP with a Chat Application - -This example shows how to use the MCP server as a knowledge base -backend for a chat application. -""" - -import requests -from typing import List, Dict, Optional - - -class ClaudeOSKnowledgeBase: - """Client for Claude OS MCP Server""" - - def __init__( - self, - base_url: str = "http://localhost:8051", - api_token: Optional[str] = None - ): - self.base_url = base_url - self.headers = {"Content-Type": "application/json"} - - if api_token: - self.headers["Authorization"] = f"Bearer {api_token}" - - def _call_tool( - self, - tool_name: str, - arguments: Dict, - kb_slug: Optional[str] = None - ) -> Dict: - """Make a JSON-RPC call to the MCP server""" - - # Use KB-specific endpoint if slug provided - url = f"{self.base_url}/mcp" - if kb_slug: - url = f"{self.base_url}/mcp/kb/{kb_slug}" - - payload = { - "jsonrpc": "2.0", - "method": "tools/call", - "params": { - "name": tool_name, - "arguments": arguments - }, - "id": 1 - } - - response = requests.post(url, json=payload, headers=self.headers) - response.raise_for_status() - - result = response.json() - if "error" in result: - raise Exception(f"MCP Error: {result['error']}") - - return result.get("result", {}) - - def search( - self, - kb_name: str, - query: str, - top_k: int = 10, - use_hybrid: bool = False, - use_rerank: bool = False - ) -> List[Dict]: - """ - Search a knowledge base for relevant information - - Args: - kb_name: Name of the knowledge base to search - query: User's question or search query - top_k: Number of results to return - use_hybrid: Enable hybrid search (vector + keyword) - use_rerank: Enable reranking for better results - - Returns: - List of relevant document chunks with metadata - """ - result = self._call_tool( - "search_knowledge_base", - { - "kb_name": kb_name, - "query": query, - "top_k": top_k, - "use_hybrid": use_hybrid, - "use_rerank": use_rerank - } - ) - - # Parse the results - if isinstance(result, dict) and "results" in result: - return result["results"] - return [] - - def list_knowledge_bases(self) -> List[Dict]: - """List all available knowledge bases""" - result = self._call_tool("list_knowledge_bases", {}) - return result.get("knowledge_bases", []) - - def get_kb_stats(self, kb_name: str) -> Dict: - """Get statistics for a knowledge base""" - result = self._call_tool("get_kb_stats", {"kb_name": kb_name}) - return result - - -class ChatWithKnowledge: - """ - Example chat application that uses Claude OS knowledge bases - """ - - def __init__(self, mcp_client: ClaudeOSKnowledgeBase): - self.mcp = mcp_client - - def answer_question( - self, - question: str, - kb_name: str, - use_hybrid: bool = True, - use_rerank: bool = True - ) -> str: - """ - Answer a user question using the knowledge base - - This is a simple example - in a real app, you'd: - 1. Search the knowledge base - 2. Pass results + question to your LLM - 3. Generate a response grounded in the retrieved docs - """ - - # 1. Search the knowledge base - results = self.mcp.search( - kb_name=kb_name, - query=question, - top_k=5, - use_hybrid=use_hybrid, - use_rerank=use_rerank - ) - - if not results: - return "I couldn't find any relevant information in the knowledge base." - - # 2. Format the context from search results - context_parts = [] - for idx, result in enumerate(results, 1): - text = result.get("text", "") - metadata = result.get("metadata", {}) - filename = metadata.get("filename", "Unknown") - score = result.get("score", 0) - - context_parts.append( - f"[{idx}] {filename} (relevance: {score:.2f})\n{text}\n" - ) - - context = "\n---\n".join(context_parts) - - # 3. In a real app, you'd call your LLM here - # For this example, just return the context - response = f"""Based on the knowledge base, here's what I found: - -{context} - -Question: {question} - -(In a production app, this would be processed by an LLM to generate a natural language answer) -""" - - return response - - def list_available_topics(self) -> str: - """List all available knowledge bases""" - kbs = self.mcp.list_knowledge_bases() - - if not kbs: - return "No knowledge bases available." - - response = "Available topics:\n\n" - for kb in kbs: - name = kb.get("name", "Unknown") - description = kb.get("description", "No description") - kb_type = kb.get("kb_type", "generic") - - response += f"- **{name}** ({kb_type})\n {description}\n\n" - - return response - - -# Example usage -if __name__ == "__main__": - # Initialize the MCP client - mcp = ClaudeOSKnowledgeBase( - base_url="http://localhost:8051", - # api_token="your-jwt-token-here" # Uncomment if auth enabled - ) - - # Create chat interface - chat = ChatWithKnowledge(mcp) - - # Example 1: List available knowledge bases - print("=" * 60) - print("AVAILABLE KNOWLEDGE BASES") - print("=" * 60) - print(chat.list_available_topics()) - print() - - # Example 2: Ask a question - print("=" * 60) - print("ASKING A QUESTION") - print("=" * 60) - - question = "How do I configure authentication?" - kb_name = "my-docs" # Change to your actual KB name - - print(f"Question: {question}") - print(f"Knowledge Base: {kb_name}") - print() - - try: - answer = chat.answer_question( - question=question, - kb_name=kb_name, - use_hybrid=True, - use_rerank=True - ) - print(answer) - except Exception as e: - print(f"Error: {e}") diff --git a/deployment/mcp-only/requirements.txt b/deployment/mcp-only/requirements.txt deleted file mode 100644 index a21e8a6..0000000 --- a/deployment/mcp-only/requirements.txt +++ /dev/null @@ -1,44 +0,0 @@ -# Minimal requirements for MCP server only (no coding tools) - -# Web Framework -fastapi>=0.104.0 -uvicorn[standard]>=0.24.0 -python-multipart>=0.0.6 - -# CORS & Rate Limiting -slowapi>=0.1.9 - -# Database & Vector Search -sqlite-vec>=0.1.0 - -# RAG Framework -llama-index-core>=0.10.0 -llama-index-embeddings-ollama>=0.1.0 -llama-index-llms-ollama>=0.1.0 - -# Reranking & Search -sentence-transformers>=2.2.0 -rank-bm25>=0.2.2 - -# Document Processing -PyMuPDF>=1.23.0 -pypdf>=3.17.0 -python-magic>=0.4.27 - -# Code Parsing -tree-sitter>=0.20.0 -tree-sitter-python>=0.20.0 -tree-sitter-javascript>=0.20.0 -tree-sitter-typescript>=0.20.0 - -# Utilities -python-dotenv>=1.0.0 -pydantic>=2.0.0 -pydantic-settings>=2.0.0 - -# Authentication (optional) -python-jose[cryptography]>=3.3.0 -passlib[bcrypt]>=1.7.4 - -# Logging -python-json-logger>=2.0.7 diff --git a/deployment/mcp-only/setup.sh b/deployment/mcp-only/setup.sh deleted file mode 100755 index a7e4766..0000000 --- a/deployment/mcp-only/setup.sh +++ /dev/null @@ -1,178 +0,0 @@ -#!/bin/bash - -# Claude OS MCP-Only Setup Script -# This script helps with first-time deployment - -set -e - -echo "🚀 Claude OS MCP-Only Deployment Setup" -echo "=======================================" -echo "" - -# Check if Docker is installed -if ! command -v docker &> /dev/null; then - echo "❌ Docker is not installed. Please install Docker first." - echo " Visit: https://docs.docker.com/get-docker/" - exit 1 -fi - -# Check if docker-compose is installed -if ! command -v docker-compose &> /dev/null; then - echo "❌ docker-compose is not installed. Please install docker-compose first." - echo " Visit: https://docs.docker.com/compose/install/" - exit 1 -fi - -echo "✅ Docker and docker-compose are installed" -echo "" - -# Check if database exists -DB_PATH="../../data/claude-os.db" -if [ ! -f "$DB_PATH" ]; then - echo "⚠️ Database not found at: $DB_PATH" - echo "" - echo " This deployment expects your existing Claude OS database." - echo " Please ensure Claude OS is set up locally first, or" - echo " adjust the volume mount in docker-compose.yml" - echo "" - read -p " Continue anyway? (y/n) " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - exit 1 - fi -else - echo "✅ Database found at: $DB_PATH" - # Get database size - DB_SIZE=$(du -h "$DB_PATH" | cut -f1) - echo " Size: $DB_SIZE" -fi -echo "" - -# Create .env from example if it doesn't exist -if [ ! -f ".env" ]; then - echo "📝 Creating .env from .env.example..." - cp .env.example .env - echo "✅ Created .env file" - echo " Please review and update .env with your settings" - echo "" -else - echo "✅ .env file already exists" - echo "" -fi - -# Prompt for CORS origins -echo "🔧 Configuration" -echo "---------------" -read -p "Enter CORS origins (comma-separated, or * for all) [*]: " CORS_INPUT -CORS_INPUT=${CORS_INPUT:-*} - -# Update .env -sed -i.bak "s|CORS_ORIGINS=.*|CORS_ORIGINS=$CORS_INPUT|" .env && rm .env.bak -echo "✅ CORS_ORIGINS set to: $CORS_INPUT" -echo "" - -# Ask about authentication -read -p "Enable authentication? (y/n) [n]: " -n 1 -r -echo -if [[ $REPLY =~ ^[Yy]$ ]]; then - # Generate a random secret - JWT_SECRET=$(openssl rand -hex 32 2>/dev/null || echo "CHANGE-THIS-SECRET-$(date +%s)") - - read -p "Enter API username [admin]: " API_USER - API_USER=${API_USER:-admin} - - read -s -p "Enter API password: " API_PASS - echo - - if [ -z "$API_PASS" ]; then - echo "❌ Password cannot be empty" - exit 1 - fi - - # Uncomment and set auth variables in .env - sed -i.bak "s|# JWT_SECRET_KEY=.*|JWT_SECRET_KEY=$JWT_SECRET|" .env && rm .env.bak - sed -i.bak "s|# JWT_ALGORITHM=.*|JWT_ALGORITHM=HS256|" .env && rm .env.bak - sed -i.bak "s|# API_USERNAME=.*|API_USERNAME=$API_USER|" .env && rm .env.bak - sed -i.bak "s|# API_PASSWORD=.*|API_PASSWORD=$API_PASS|" .env && rm .env.bak - - echo "✅ Authentication enabled" -else - echo "⚠️ Authentication disabled (not recommended for production)" -fi -echo "" - -# Start services -echo "🐳 Starting Docker containers..." -echo "-------------------------------" -docker-compose up -d - -echo "" -echo "⏳ Waiting for services to start..." -sleep 5 - -# Wait for Ollama to be ready -echo "Checking Ollama status..." -OLLAMA_READY=0 -for i in {1..30}; do - if docker exec claude-os-ollama ollama list &>/dev/null; then - OLLAMA_READY=1 - break - fi - echo " Waiting for Ollama... ($i/30)" - sleep 2 -done - -if [ $OLLAMA_READY -eq 0 ]; then - echo "⚠️ Ollama is taking longer than expected to start" - echo " You can check logs with: docker-compose logs ollama" -else - echo "✅ Ollama is ready" -fi -echo "" - -# Pull required models -echo "📥 Pulling required Ollama models..." -echo "-----------------------------------" -echo "This may take a few minutes on first run..." -echo "" - -echo "Pulling nomic-embed-text (embeddings)..." -docker exec claude-os-ollama ollama pull nomic-embed-text - -echo "Pulling llama3.1:latest (LLM)..." -docker exec claude-os-ollama ollama pull llama3.1:latest - -echo "" -echo "✅ Models downloaded successfully" -echo "" - -# Check MCP server health -echo "🏥 Checking MCP server health..." -sleep 3 - -if curl -f http://localhost:8051/health &>/dev/null; then - echo "✅ MCP server is healthy!" -else - echo "⚠️ MCP server is not responding yet" - echo " Check logs with: docker-compose logs mcp-server" -fi - -echo "" -echo "=========================================" -echo "✨ Setup Complete!" -echo "=========================================" -echo "" -echo "Your MCP server is now running at:" -echo " http://localhost:8051" -echo "" -echo "Test it with:" -echo " curl http://localhost:8051/health" -echo "" -echo "View logs:" -echo " docker-compose logs -f mcp-server" -echo "" -echo "Stop services:" -echo " docker-compose down" -echo "" -echo "See README.md for usage examples and API documentation" -echo ""