Skip to content

feat: enhance chat agent intelligence for name-based queries #81

feat: enhance chat agent intelligence for name-based queries

feat: enhance chat agent intelligence for name-based queries #81

Workflow file for this run

name: MCP Server CI/CD Pipeline
on:
push:
branches: [ main, develop ]
paths:
- 'apps/mcp/**'
- 'packages/auth/**'
- '.github/workflows/mcp-deploy.yml'
pull_request:
branches: [ main, develop ]
paths:
- 'apps/mcp/**'
- 'packages/auth/**'
env:
PYTHON_VERSION: '3.11'
DOCKER_IMAGE: 'wildeditor-mcp'
REGISTRY: 'ghcr.io'
jobs:
# Test MCP server
test-mcp:
name: Test MCP Server
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Cache pip dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-mcp-${{ hashFiles('apps/mcp/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-mcp-
- name: Install dependencies
run: |
# Install auth package first
pip install -e packages/auth
cd apps/mcp
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Lint with flake8
run: |
pip install flake8
flake8 apps/mcp/src --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 apps/mcp/src --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Type check with mypy
run: |
pip install mypy
mypy apps/mcp/src --ignore-missing-imports || true
- name: Run tests
run: |
cd apps/mcp
# Set test environment variables
export WILDEDITOR_MCP_KEY="test-mcp-key-for-github-actions"
export WILDEDITOR_API_KEY="test-backend-key-for-github-actions"
export WILDEDITOR_BACKEND_URL="http://localhost:8000"
export TESTING="1"
# Run tests
PYTHONPATH=. pytest tests/ -v --tb=short
- name: Test server startup
run: |
cd apps/mcp
# Set environment variables for testing
export WILDEDITOR_MCP_KEY="test-startup-key"
export WILDEDITOR_API_KEY="test-startup-backend-key"
export WILDEDITOR_BACKEND_URL="http://localhost:8000"
export TESTING="1"
# Run a basic smoke test to ensure the app can start
python -c "
import sys
import os
sys.path.insert(0, '.')
os.environ['WILDEDITOR_MCP_KEY'] = 'test-startup-key'
os.environ['WILDEDITOR_API_KEY'] = 'test-startup-backend-key'
os.environ['WILDEDITOR_BACKEND_URL'] = 'http://localhost:8000'
os.environ['TESTING'] = '1'
from src.main import app
from fastapi.testclient import TestClient
client = TestClient(app)
response = client.get('/health')
assert response.status_code == 200
print('✅ MCP server startup test passed')
"
- name: Security check with bandit
run: |
pip install bandit
bandit -r apps/mcp/src -f json -o mcp-bandit-report.json || true
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: mcp-test-results
path: |
mcp-bandit-report.json
retention-days: 7
# Build Docker image
build-mcp-image:
name: Build MCP Docker Image
runs-on: ubuntu-latest
needs: test-mcp
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/luminarimud/wildeditor-mcp
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: apps/mcp/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Output image digest
run: echo ${{ steps.build.outputs.digest }}
# Deploy to production server
deploy-mcp-production:
name: Deploy MCP to Production
runs-on: ubuntu-latest
needs: [test-mcp, build-mcp-image]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
environment:
name: production
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: Add server to known hosts
run: |
mkdir -p ~/.ssh
ssh-keyscan -H ${{ secrets.PRODUCTION_HOST }} >> ~/.ssh/known_hosts
chmod 600 ~/.ssh/known_hosts
- name: Test SSH connection
run: |
echo "Testing SSH connection to ${{ secrets.PRODUCTION_HOST }}..."
ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no ${{ secrets.PRODUCTION_USER }}@${{ secrets.PRODUCTION_HOST }} "echo 'SSH connection successful'"
- name: Setup MCP server environment
run: |
echo "Setting up MCP server environment..."
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=30 ${{ secrets.PRODUCTION_USER }}@${{ secrets.PRODUCTION_HOST }} << 'SETUP_EOF'
# Create MCP directories in user's home directory (no sudo needed)
mkdir -p ~/wildeditor-mcp
mkdir -p ~/logs/wildeditor-mcp
# Check if port 8001 is available
echo "🌐 Checking if port 8001 is available..."
if ss -tlnp | grep :8001; then
echo "⚠️ Port 8001 is already in use:"
ss -tlnp | grep :8001
else
echo "✅ Port 8001 is available"
fi
echo "✅ MCP server environment setup complete"
SETUP_EOF
- name: Deploy MCP server to production
env:
WILDEDITOR_MCP_KEY: ${{ secrets.WILDEDITOR_MCP_KEY }}
WILDEDITOR_API_KEY: ${{ secrets.WILDEDITOR_API_KEY }}
# AI Provider Keys
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
AI_PROVIDER: ${{ secrets.AI_PROVIDER }}
OPENAI_MODEL: ${{ secrets.OPENAI_MODEL }}
ANTHROPIC_MODEL: ${{ secrets.ANTHROPIC_MODEL }}
DEEPSEEK_MODEL: ${{ secrets.DEEPSEEK_MODEL }}
OLLAMA_BASE_URL: ${{ secrets.OLLAMA_BASE_URL }}
OLLAMA_MODEL: ${{ secrets.OLLAMA_MODEL }}
run: |
# Check if MCP keys are provided
if [ -z "$WILDEDITOR_MCP_KEY" ]; then
echo "❌ WILDEDITOR_MCP_KEY secret is not set in GitHub repository"
echo "Please add it in Settings → Secrets and variables → Actions"
echo "Generate using: PowerShell -Command \"\$bytes = New-Object byte[] 32; (New-Object Security.Cryptography.RNGCryptoServiceProvider).GetBytes(\$bytes); [Convert]::ToBase64String(\$bytes)\""
exit 1
fi
if [ -z "$WILDEDITOR_API_KEY" ]; then
echo "❌ WILDEDITOR_API_KEY secret is not set in GitHub repository"
echo "Please add it in Settings → Secrets and variables → Actions"
echo "Generate using: PowerShell -Command \"\$bytes = New-Object byte[] 32; (New-Object Security.Cryptography.RNGCryptoServiceProvider).GetBytes(\$bytes); [Convert]::ToBase64String(\$bytes)\""
exit 1
fi
echo "✅ MCP keys are configured"
# Create MCP deployment script
cat > deploy-mcp.sh << 'EOF'
#!/bin/bash
set -e
echo "🚀 Starting MCP server deployment..."
# Configuration
DOCKER_IMAGE="ghcr.io/luminarimud/wildeditor-mcp:latest"
CONTAINER_NAME="wildeditor-mcp"
# Keys will be passed as environment variables
if [ -z "$MCP_KEY" ]; then
echo "❌ MCP key not provided to deployment script"
exit 1
fi
if [ -z "$MCP_BACKEND_KEY" ]; then
echo "❌ MCP backend key not provided to deployment script"
exit 1
fi
echo "✅ MCP key received: ${MCP_KEY:0:8}..."
echo "✅ MCP backend key received: ${MCP_BACKEND_KEY:0:8}..."
# Check Docker access
if groups | grep -q docker; then
DOCKER_CMD="docker"
echo "✅ User is in docker group"
elif sudo -n true 2>/dev/null; then
DOCKER_CMD="sudo docker"
echo "✅ Passwordless sudo available"
else
echo "❌ Error: User needs to be in docker group or have passwordless sudo access"
exit 1
fi
# Debug: Check if directory exists and show current working directory
echo "🔍 Current working directory: $(pwd)"
echo "🔍 Target directory: ~/wildeditor-mcp"
if [ -d "$HOME/wildeditor-mcp" ]; then
echo "✅ Target directory exists"
ls -la ~/wildeditor-mcp
else
echo "❌ Target directory does not exist, creating it..."
mkdir -p ~/wildeditor-mcp
echo "✅ Directory created in home directory"
fi
echo "🔍 Changing to target directory..."
cd ~/wildeditor-mcp
echo "✅ Now in directory: $(pwd)"
# Login to GitHub Container Registry
echo "GITHUB_TOKEN_PLACEHOLDER" | $DOCKER_CMD login ghcr.io -u GITHUB_ACTOR_PLACEHOLDER --password-stdin
# Pull latest MCP image
echo "📦 Pulling latest MCP Docker image..."
$DOCKER_CMD pull $DOCKER_IMAGE
# Stop existing MCP container
echo "🛑 Stopping existing MCP container..."
$DOCKER_CMD stop $CONTAINER_NAME || true
$DOCKER_CMD rm $CONTAINER_NAME || true
# Start new MCP container with host networking (same as backend)
echo "🏃 Starting new MCP container with host networking..."
$DOCKER_CMD run -d \
--name $CONTAINER_NAME \
--restart unless-stopped \
--network host \
-e WILDEDITOR_MCP_KEY="$MCP_KEY" \
-e WILDEDITOR_API_KEY="$MCP_BACKEND_KEY" \
-e WILDEDITOR_BACKEND_URL="http://localhost:8000" \
-e ENVIRONMENT="production" \
-e DEBUG="false" \
-e PORT="8001" \
-e LOG_LEVEL="INFO" \
-e AI_PROVIDER="${AI_PROVIDER:-none}" \
-e OPENAI_API_KEY="$OPENAI_API_KEY" \
-e OPENAI_MODEL="${OPENAI_MODEL:-gpt-4-turbo-preview}" \
-e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
-e ANTHROPIC_MODEL="${ANTHROPIC_MODEL:-claude-3-opus-20240229}" \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-e DEEPSEEK_MODEL="${DEEPSEEK_MODEL:-deepseek-chat}" \
-e OLLAMA_BASE_URL="$OLLAMA_BASE_URL" \
-e OLLAMA_MODEL="${OLLAMA_MODEL:-llama2}" \
-v $HOME/logs/wildeditor-mcp:/var/log/wildeditor-mcp \
$DOCKER_IMAGE
# Wait for container to be healthy
echo "🏥 Waiting for health check..."
for i in {1..30}; do
# First check if container is running
if ! $DOCKER_CMD ps | grep -q $CONTAINER_NAME; then
echo "❌ Container is not running"
$DOCKER_CMD logs --tail 10 $CONTAINER_NAME
exit 1
fi
# Try health check with curl from host
if curl -s --connect-timeout 5 --max-time 10 http://localhost:8001/health >/dev/null 2>&1; then
echo "✅ MCP container is healthy!"
break
fi
if [ $i -eq 30 ]; then
echo "❌ MCP container failed to become healthy after 60 seconds"
echo "🔍 Container status:"
$DOCKER_CMD ps -a | grep $CONTAINER_NAME
echo "🔍 Container logs:"
$DOCKER_CMD logs --tail 20 $CONTAINER_NAME
echo "🔍 Port status:"
ss -tlnp | grep :8001 || echo "Port 8001 not listening"
echo "🔍 Manual health check:"
curl -v http://localhost:8001/health || echo "Curl failed"
exit 1
fi
echo "Waiting... ($i/30)"
sleep 2
done
# Test MCP endpoints
echo "🧪 Testing MCP endpoints..."
if curl -s --connect-timeout 5 --max-time 10 http://localhost:8001/health >/dev/null; then
echo "✅ Health endpoint working"
else
echo "❌ Health endpoint failed"
exit 1
fi
# Test authenticated endpoint
if curl -s --connect-timeout 5 --max-time 10 -H "X-API-Key: $MCP_KEY" http://localhost:8001/mcp/status >/dev/null; then
echo "✅ Authenticated endpoints working"
else
echo "⚠️ Authenticated endpoint test failed (but health check passed)"
fi
# Cleanup old images
echo "🧹 Cleaning up old images..."
$DOCKER_CMD image prune -f
echo "🎉 MCP server deployment completed successfully!"
EOF
# Replace placeholders in the script
sed -i "s/GITHUB_TOKEN_PLACEHOLDER/${{ secrets.GITHUB_TOKEN }}/g" deploy-mcp.sh
sed -i "s/GITHUB_ACTOR_PLACEHOLDER/${{ github.actor }}/g" deploy-mcp.sh
# Copy and execute MCP deployment script with environment variables
echo "Copying MCP deployment script to server..."
scp -o StrictHostKeyChecking=no -o ConnectTimeout=30 deploy-mcp.sh ${{ secrets.PRODUCTION_USER }}@${{ secrets.PRODUCTION_HOST }}:/tmp/
echo "Executing MCP deployment script on server..."
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=30 ${{ secrets.PRODUCTION_USER }}@${{ secrets.PRODUCTION_HOST }} "
chmod +x /tmp/deploy-mcp.sh
export MCP_KEY='$WILDEDITOR_MCP_KEY'
export MCP_BACKEND_KEY='$WILDEDITOR_API_KEY'
export AI_PROVIDER='${AI_PROVIDER:-none}'
export OPENAI_API_KEY='$OPENAI_API_KEY'
export OPENAI_MODEL='${OPENAI_MODEL:-gpt-4-turbo-preview}'
export ANTHROPIC_API_KEY='$ANTHROPIC_API_KEY'
export ANTHROPIC_MODEL='${ANTHROPIC_MODEL:-claude-3-opus-20240229}'
export DEEPSEEK_API_KEY='$DEEPSEEK_API_KEY'
export DEEPSEEK_MODEL='${DEEPSEEK_MODEL:-deepseek-chat}'
export OLLAMA_BASE_URL='$OLLAMA_BASE_URL'
export OLLAMA_MODEL='${OLLAMA_MODEL:-llama2}'
/tmp/deploy-mcp.sh
"
- name: Verify MCP deployment
run: |
# Wait a moment for the service to be fully ready
sleep 10
echo "🔍 Verifying MCP deployment..."
# Test from within the server
echo "Testing MCP health endpoint from server..."
SERVER_HEALTH_CHECK=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=30 ${{ secrets.PRODUCTION_USER }}@${{ secrets.PRODUCTION_HOST }} "
echo '🏥 Testing MCP health endpoint from server:'
if curl -s --connect-timeout 5 --max-time 10 http://localhost:8001/health; then
echo ''
echo '✅ MCP server-side health check PASSED'
echo ''
echo '🔐 Testing MCP authentication endpoint:'
if curl -s --connect-timeout 5 --max-time 10 -H 'X-API-Key: $WILDEDITOR_MCP_KEY' http://localhost:8001/mcp/status | grep -q 'mcp_server'; then
echo '✅ MCP authentication endpoint PASSED'
else
echo '⚠️ MCP authentication endpoint test failed (but health check passed)'
fi
exit 0
else
echo ''
echo '❌ MCP server-side health check FAILED'
echo 'Container logs:'
docker logs --tail 10 wildeditor-mcp || true
exit 1
fi
")
if [ $? -eq 0 ]; then
echo "✅ MCP server-side health check passed!"
else
echo "❌ MCP server-side health check failed!"
exit 1
fi
echo ""
echo "✅ MCP deployment verification completed successfully!"
echo "The MCP server is running and responding to health checks on port 8001"
- name: Create MCP deployment notification
uses: actions/github-script@v7
with:
script: |
const output = `#### 🤖 MCP Server Deployment Successful!\n
- **Environment**: Production
- **Version**: \`${{ github.sha }}\`
- **MCP API URL**: http://${{ secrets.PRODUCTION_HOST }}:8001
- **Health Check**: ✅ Passing
- **Authentication**: 🔐 MCP Key Required
- **AI Provider**: ${process.env.AI_PROVIDER || 'Template Fallback'}
- **Supported Providers**: OpenAI, Anthropic, DeepSeek, Ollama
- **Tools**: 14 Wilderness Management Tools (5 with AI)
- **Resources**: 7 Knowledge Resources
- **Prompts**: 5 AI Content Generation Templates
- **Deployed by**: @${{ github.actor }}
The MCP server is now live with AI-powered description generation!
**For AI Agents:**
- Connect to: \`http://${{ secrets.PRODUCTION_HOST }}:8001\`
- Use the configured MCP key for authentication
- Test connection: \`curl -H "X-API-Key: YOUR_MCP_KEY" http://${{ secrets.PRODUCTION_HOST }}:8001/mcp/status\`
**Available Tools:**
- \`analyze_region\` - Deep wilderness region analysis
- \`find_path\` - Pathfinding between regions
- \`search_regions\` - Advanced region search
- \`create_region\` - New region creation
- \`validate_connections\` - Connection consistency checking`;
github.rest.repos.createCommitComment({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: '${{ github.sha }}',
body: output
})
# Notify deployment status
notify-mcp:
name: Notify MCP Deployment Status
runs-on: ubuntu-latest
needs: [deploy-mcp-production]
if: always() && github.ref == 'refs/heads/main'
steps:
- name: Log MCP deployment result
run: |
if [ "${{ needs.deploy-mcp-production.result }}" == "success" ]; then
echo "🚀 Wildeditor MCP Server deployed successfully!"
else
echo "❌ Wildeditor MCP Server deployment failed!"
exit 1
fi