generated from personal-projects/leo-claude-mktplace
Create deployment documentation
This commit provides comprehensive deployment documentation for production use. README.md updates: - Completely rewritten to reflect HTTP wrapper architecture - Clear distinction from standalone MCP server - Architecture diagram showing HTTP → wrapper → MCP → Gitea flow - Quick start guide with Docker - Configuration reference (required and optional) - HTTP endpoints documentation - Claude Desktop integration instructions - Troubleshooting section for common issues - Security considerations - References to DEPLOYMENT.md for advanced scenarios DEPLOYMENT.md (new): - Complete production deployment guide - Docker deployment (quick start and production config) - Security best practices: - Authentication setup - HTTPS configuration - Secrets management - Network isolation - Token rotation - Monitoring and health checks - Reverse proxy configurations (Nginx, Caddy, Traefik) - Cloud deployment guides: - AWS EC2 and ECS - Google Cloud Run - Azure Container Instances - Kubernetes deployment with full manifests - Troubleshooting production issues - Scaling considerations (horizontal, load balancing, caching) - Backup and disaster recovery - Production deployment checklist This documentation enables users to: 1. Get started quickly with Docker 2. Understand the architecture 3. Deploy securely in production 4. Scale and monitor the service 5. Troubleshoot common issues The documentation is deployment-focused and production-ready, covering real-world scenarios from local testing to enterprise cloud deployment. Closes #16 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
712
DEPLOYMENT.md
Normal file
712
DEPLOYMENT.md
Normal file
@@ -0,0 +1,712 @@
|
||||
# Deployment Guide
|
||||
|
||||
This guide covers production deployment of the Gitea HTTP MCP Wrapper in various environments.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Prerequisites](#prerequisites)
|
||||
2. [Docker Deployment](#docker-deployment)
|
||||
3. [Security Best Practices](#security-best-practices)
|
||||
4. [Monitoring and Health Checks](#monitoring-and-health-checks)
|
||||
5. [Reverse Proxy Configuration](#reverse-proxy-configuration)
|
||||
6. [Cloud Deployment](#cloud-deployment)
|
||||
7. [Kubernetes Deployment](#kubernetes-deployment)
|
||||
8. [Troubleshooting](#troubleshooting)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Required
|
||||
|
||||
- Docker and Docker Compose (for Docker deployment)
|
||||
- Gitea instance with API access
|
||||
- Gitea API token with appropriate permissions
|
||||
- Network connectivity between wrapper and Gitea instance
|
||||
|
||||
### Recommended
|
||||
|
||||
- HTTPS-capable reverse proxy (Nginx, Caddy, Traefik)
|
||||
- Secrets management solution (not `.env` files in production)
|
||||
- Monitoring and logging infrastructure
|
||||
- Firewall or VPN for network security
|
||||
|
||||
## Docker Deployment
|
||||
|
||||
### Quick Start
|
||||
|
||||
1. **Clone the repository:**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/lmiranda/gitea-mcp-remote.git
|
||||
cd gitea-mcp-remote
|
||||
```
|
||||
|
||||
2. **Create configuration:**
|
||||
|
||||
```bash
|
||||
cp .env.docker.example .env
|
||||
nano .env # Edit with your values
|
||||
```
|
||||
|
||||
Required configuration:
|
||||
```bash
|
||||
GITEA_URL=https://gitea.example.com
|
||||
GITEA_TOKEN=your_gitea_api_token
|
||||
GITEA_OWNER=your_username_or_org
|
||||
GITEA_REPO=your_default_repo
|
||||
AUTH_TOKEN=your_bearer_token # Recommended
|
||||
```
|
||||
|
||||
3. **Start the service:**
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Verify deployment:**
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/health
|
||||
```
|
||||
|
||||
### Production Configuration
|
||||
|
||||
For production, use a more robust `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
gitea-mcp-wrapper:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: gitea-mcp-wrapper:latest
|
||||
container_name: gitea-mcp-wrapper
|
||||
restart: always
|
||||
ports:
|
||||
- "127.0.0.1:8000:8000" # Bind to localhost only
|
||||
environment:
|
||||
- GITEA_URL=${GITEA_URL}
|
||||
- GITEA_TOKEN=${GITEA_TOKEN}
|
||||
- GITEA_OWNER=${GITEA_OWNER}
|
||||
- GITEA_REPO=${GITEA_REPO}
|
||||
- HTTP_HOST=0.0.0.0
|
||||
- HTTP_PORT=8000
|
||||
- AUTH_TOKEN=${AUTH_TOKEN}
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health').read()"]
|
||||
interval: 30s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
start_period: 5s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
networks:
|
||||
- gitea-mcp-network
|
||||
|
||||
networks:
|
||||
gitea-mcp-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### Docker Build Options
|
||||
|
||||
**Build the image:**
|
||||
|
||||
```bash
|
||||
docker build -t gitea-mcp-wrapper:latest .
|
||||
```
|
||||
|
||||
**Build with specific Python version:**
|
||||
|
||||
```bash
|
||||
docker build --build-arg PYTHON_VERSION=3.11 -t gitea-mcp-wrapper:latest .
|
||||
```
|
||||
|
||||
**Tag for registry:**
|
||||
|
||||
```bash
|
||||
docker tag gitea-mcp-wrapper:latest registry.example.com/gitea-mcp-wrapper:latest
|
||||
docker push registry.example.com/gitea-mcp-wrapper:latest
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### 1. Use Authentication
|
||||
|
||||
Always set `AUTH_TOKEN` in production:
|
||||
|
||||
```bash
|
||||
# Generate a secure token
|
||||
openssl rand -base64 32
|
||||
|
||||
# Add to .env
|
||||
AUTH_TOKEN=<generated_token>
|
||||
```
|
||||
|
||||
### 2. Use HTTPS
|
||||
|
||||
Never expose the wrapper directly to the internet without HTTPS. Use a reverse proxy (see below).
|
||||
|
||||
### 3. Network Isolation
|
||||
|
||||
- Bind to localhost only (`127.0.0.1`) if using a reverse proxy
|
||||
- Use Docker networks to isolate services
|
||||
- Consider VPN or private networking for access
|
||||
|
||||
### 4. Secrets Management
|
||||
|
||||
Don't use `.env` files in production. Use Docker secrets, Kubernetes secrets, or a secrets manager:
|
||||
|
||||
**Docker Secrets Example:**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
gitea-mcp-wrapper:
|
||||
secrets:
|
||||
- gitea_token
|
||||
- auth_token
|
||||
environment:
|
||||
- GITEA_TOKEN_FILE=/run/secrets/gitea_token
|
||||
- AUTH_TOKEN_FILE=/run/secrets/auth_token
|
||||
|
||||
secrets:
|
||||
gitea_token:
|
||||
external: true
|
||||
auth_token:
|
||||
external: true
|
||||
```
|
||||
|
||||
### 5. Regular Updates
|
||||
|
||||
- Rotate Gitea API token regularly
|
||||
- Rotate AUTH_TOKEN regularly
|
||||
- Keep Docker base image updated
|
||||
- Update dependencies: `pip install --upgrade -r requirements.txt`
|
||||
|
||||
### 6. Minimal Permissions
|
||||
|
||||
Grant the Gitea API token only the minimum required permissions:
|
||||
|
||||
- Repository read/write
|
||||
- Issue management
|
||||
- Label management
|
||||
- Milestone management
|
||||
|
||||
Avoid granting admin or organization-level permissions.
|
||||
|
||||
## Monitoring and Health Checks
|
||||
|
||||
### Health Check Endpoints
|
||||
|
||||
The wrapper provides three health check endpoints:
|
||||
|
||||
```bash
|
||||
GET /health
|
||||
GET /healthz
|
||||
GET /ping
|
||||
```
|
||||
|
||||
All return `{"status": "healthy"}` with HTTP 200 when the server is operational.
|
||||
|
||||
### Docker Health Checks
|
||||
|
||||
Docker automatically monitors the health check and can restart if unhealthy:
|
||||
|
||||
```yaml
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||
interval: 30s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
start_period: 5s
|
||||
```
|
||||
|
||||
### Monitoring Integration
|
||||
|
||||
**Prometheus metrics:** (Not yet implemented, but can be added)
|
||||
|
||||
**Log monitoring:**
|
||||
|
||||
```bash
|
||||
# View logs
|
||||
docker-compose logs -f gitea-mcp-wrapper
|
||||
|
||||
# JSON structured logs
|
||||
docker logs gitea-mcp-wrapper --tail 100
|
||||
```
|
||||
|
||||
**Uptime monitoring:**
|
||||
|
||||
Use tools like UptimeRobot, Pingdom, or Datadog to monitor `/health` endpoint.
|
||||
|
||||
## Reverse Proxy Configuration
|
||||
|
||||
### Nginx
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name mcp.example.com;
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||
ssl_certificate_key /etc/nginx/ssl/key.pem;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Pass through Authorization header
|
||||
proxy_set_header Authorization $http_authorization;
|
||||
proxy_pass_header Authorization;
|
||||
|
||||
# WebSocket support (if needed in future)
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
# Health check endpoint (optional, can bypass auth)
|
||||
location /health {
|
||||
proxy_pass http://127.0.0.1:8000/health;
|
||||
access_log off;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Caddy
|
||||
|
||||
```caddyfile
|
||||
mcp.example.com {
|
||||
reverse_proxy localhost:8000 {
|
||||
# Pass through Authorization header
|
||||
header_up Authorization {>Authorization}
|
||||
}
|
||||
|
||||
# Optional: Rate limiting
|
||||
rate_limit {
|
||||
zone mcp_zone
|
||||
rate 100r/m
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Traefik
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
gitea-mcp-wrapper:
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.mcp.rule=Host(`mcp.example.com`)"
|
||||
- "traefik.http.routers.mcp.entrypoints=websecure"
|
||||
- "traefik.http.routers.mcp.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.mcp.loadbalancer.server.port=8000"
|
||||
```
|
||||
|
||||
## Cloud Deployment
|
||||
|
||||
### AWS EC2
|
||||
|
||||
1. **Launch EC2 instance:**
|
||||
- Amazon Linux 2 or Ubuntu 22.04
|
||||
- t3.micro or larger
|
||||
- Security group: Allow port 443 (HTTPS)
|
||||
|
||||
2. **Install Docker:**
|
||||
|
||||
```bash
|
||||
sudo yum update -y
|
||||
sudo yum install -y docker
|
||||
sudo service docker start
|
||||
sudo usermod -aG docker ec2-user
|
||||
```
|
||||
|
||||
3. **Deploy wrapper:**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/lmiranda/gitea-mcp-remote.git
|
||||
cd gitea-mcp-remote
|
||||
cp .env.docker.example .env
|
||||
nano .env # Configure
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
4. **Configure Nginx or ALB for HTTPS**
|
||||
|
||||
### AWS ECS (Fargate)
|
||||
|
||||
1. **Create task definition:**
|
||||
|
||||
```json
|
||||
{
|
||||
"family": "gitea-mcp-wrapper",
|
||||
"networkMode": "awsvpc",
|
||||
"requiresCompatibilities": ["FARGATE"],
|
||||
"cpu": "256",
|
||||
"memory": "512",
|
||||
"containerDefinitions": [
|
||||
{
|
||||
"name": "gitea-mcp-wrapper",
|
||||
"image": "your-ecr-repo/gitea-mcp-wrapper:latest",
|
||||
"portMappings": [
|
||||
{
|
||||
"containerPort": 8000,
|
||||
"protocol": "tcp"
|
||||
}
|
||||
],
|
||||
"environment": [
|
||||
{"name": "GITEA_URL", "value": "https://gitea.example.com"},
|
||||
{"name": "HTTP_HOST", "value": "0.0.0.0"},
|
||||
{"name": "HTTP_PORT", "value": "8000"}
|
||||
],
|
||||
"secrets": [
|
||||
{
|
||||
"name": "GITEA_TOKEN",
|
||||
"valueFrom": "arn:aws:secretsmanager:region:account:secret:gitea-token"
|
||||
},
|
||||
{
|
||||
"name": "AUTH_TOKEN",
|
||||
"valueFrom": "arn:aws:secretsmanager:region:account:secret:auth-token"
|
||||
}
|
||||
],
|
||||
"healthCheck": {
|
||||
"command": ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"],
|
||||
"interval": 30,
|
||||
"timeout": 5,
|
||||
"retries": 3,
|
||||
"startPeriod": 10
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
2. **Create ECS service with ALB**
|
||||
|
||||
### Google Cloud Run
|
||||
|
||||
1. **Build and push image:**
|
||||
|
||||
```bash
|
||||
gcloud builds submit --tag gcr.io/PROJECT_ID/gitea-mcp-wrapper
|
||||
```
|
||||
|
||||
2. **Deploy:**
|
||||
|
||||
```bash
|
||||
gcloud run deploy gitea-mcp-wrapper \
|
||||
--image gcr.io/PROJECT_ID/gitea-mcp-wrapper \
|
||||
--platform managed \
|
||||
--region us-central1 \
|
||||
--allow-unauthenticated \
|
||||
--set-env-vars GITEA_URL=https://gitea.example.com \
|
||||
--set-secrets GITEA_TOKEN=gitea-token:latest,AUTH_TOKEN=auth-token:latest \
|
||||
--port 8000
|
||||
```
|
||||
|
||||
### Azure Container Instances
|
||||
|
||||
```bash
|
||||
az container create \
|
||||
--resource-group myResourceGroup \
|
||||
--name gitea-mcp-wrapper \
|
||||
--image your-registry/gitea-mcp-wrapper:latest \
|
||||
--ports 8000 \
|
||||
--dns-name-label gitea-mcp \
|
||||
--environment-variables \
|
||||
GITEA_URL=https://gitea.example.com \
|
||||
HTTP_HOST=0.0.0.0 \
|
||||
HTTP_PORT=8000 \
|
||||
--secure-environment-variables \
|
||||
GITEA_TOKEN=your_token \
|
||||
AUTH_TOKEN=your_auth_token
|
||||
```
|
||||
|
||||
## Kubernetes Deployment
|
||||
|
||||
### Deployment Manifest
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: gitea-mcp-wrapper
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: gitea-mcp-wrapper
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: gitea-mcp-wrapper
|
||||
spec:
|
||||
containers:
|
||||
- name: gitea-mcp-wrapper
|
||||
image: your-registry/gitea-mcp-wrapper:latest
|
||||
ports:
|
||||
- containerPort: 8000
|
||||
env:
|
||||
- name: GITEA_URL
|
||||
value: "https://gitea.example.com"
|
||||
- name: HTTP_HOST
|
||||
value: "0.0.0.0"
|
||||
- name: HTTP_PORT
|
||||
value: "8000"
|
||||
- name: GITEA_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-secrets
|
||||
key: token
|
||||
- name: AUTH_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-secrets
|
||||
key: auth-token
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8000
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 30
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8000
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "200m"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: gitea-mcp-wrapper
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: gitea-mcp-wrapper
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 8000
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: gitea-mcp-wrapper
|
||||
namespace: default
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
spec:
|
||||
tls:
|
||||
- hosts:
|
||||
- mcp.example.com
|
||||
secretName: mcp-tls
|
||||
rules:
|
||||
- host: mcp.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: gitea-mcp-wrapper
|
||||
port:
|
||||
number: 80
|
||||
```
|
||||
|
||||
### Secrets Management
|
||||
|
||||
```bash
|
||||
# Create secret
|
||||
kubectl create secret generic gitea-secrets \
|
||||
--from-literal=token=your_gitea_token \
|
||||
--from-literal=auth-token=your_auth_token \
|
||||
--namespace=default
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Container Won't Start
|
||||
|
||||
```bash
|
||||
# Check logs
|
||||
docker-compose logs gitea-mcp-wrapper
|
||||
|
||||
# Check container status
|
||||
docker-compose ps
|
||||
|
||||
# Rebuild image
|
||||
docker-compose build --no-cache
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Health Check Failing
|
||||
|
||||
```bash
|
||||
# Test health endpoint directly
|
||||
docker exec gitea-mcp-wrapper curl http://localhost:8000/health
|
||||
|
||||
# Check if server is listening
|
||||
docker exec gitea-mcp-wrapper netstat -tlnp
|
||||
```
|
||||
|
||||
### Cannot Reach Gitea from Container
|
||||
|
||||
```bash
|
||||
# Test connectivity
|
||||
docker exec gitea-mcp-wrapper curl -v https://gitea.example.com
|
||||
|
||||
# Check DNS resolution
|
||||
docker exec gitea-mcp-wrapper nslookup gitea.example.com
|
||||
|
||||
# For docker-compose, ensure network allows egress
|
||||
```
|
||||
|
||||
### High Memory Usage
|
||||
|
||||
```bash
|
||||
# Check container stats
|
||||
docker stats gitea-mcp-wrapper
|
||||
|
||||
# Adjust resource limits in docker-compose.yml
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 256M
|
||||
```
|
||||
|
||||
### Authentication Failures
|
||||
|
||||
```bash
|
||||
# Verify AUTH_TOKEN is set
|
||||
docker exec gitea-mcp-wrapper printenv AUTH_TOKEN
|
||||
|
||||
# Test with curl
|
||||
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:8000/tools/list
|
||||
|
||||
# Check logs for auth failures
|
||||
docker-compose logs gitea-mcp-wrapper | grep -i auth
|
||||
```
|
||||
|
||||
## Scaling Considerations
|
||||
|
||||
### Horizontal Scaling
|
||||
|
||||
The wrapper is stateless and can be scaled horizontally:
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
gitea-mcp-wrapper:
|
||||
deploy:
|
||||
replicas: 3
|
||||
```
|
||||
|
||||
Or in Kubernetes:
|
||||
|
||||
```bash
|
||||
kubectl scale deployment gitea-mcp-wrapper --replicas=5
|
||||
```
|
||||
|
||||
### Load Balancing
|
||||
|
||||
Use a load balancer to distribute traffic:
|
||||
- Docker Swarm: Built-in load balancing
|
||||
- Kubernetes: Service with multiple pods
|
||||
- Cloud: AWS ALB, GCP Load Balancer, Azure Load Balancer
|
||||
|
||||
### Caching
|
||||
|
||||
Consider caching responses to reduce Gitea API load:
|
||||
- Add Redis or Memcached
|
||||
- Cache tool list responses
|
||||
- Cache frequently accessed issues/labels
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
Implement rate limiting at reverse proxy level to prevent API abuse:
|
||||
|
||||
**Nginx:**
|
||||
```nginx
|
||||
limit_req_zone $binary_remote_addr zone=mcp:10m rate=10r/s;
|
||||
limit_req zone=mcp burst=20 nodelay;
|
||||
```
|
||||
|
||||
**Caddy:**
|
||||
```caddyfile
|
||||
rate_limit {
|
||||
rate 100r/m
|
||||
}
|
||||
```
|
||||
|
||||
## Backup and Disaster Recovery
|
||||
|
||||
### Configuration Backup
|
||||
|
||||
```bash
|
||||
# Backup .env file
|
||||
cp .env .env.backup.$(date +%Y%m%d)
|
||||
|
||||
# Backup docker-compose.yml
|
||||
cp docker-compose.yml docker-compose.yml.backup.$(date +%Y%m%d)
|
||||
```
|
||||
|
||||
### Image Backup
|
||||
|
||||
```bash
|
||||
# Save Docker image
|
||||
docker save gitea-mcp-wrapper:latest | gzip > gitea-mcp-wrapper-backup.tar.gz
|
||||
|
||||
# Load Docker image
|
||||
docker load < gitea-mcp-wrapper-backup.tar.gz
|
||||
```
|
||||
|
||||
### Recovery Plan
|
||||
|
||||
1. Restore configuration files
|
||||
2. Rebuild or load Docker image
|
||||
3. Start services: `docker-compose up -d`
|
||||
4. Verify health: `curl http://localhost:8000/health`
|
||||
5. Test authentication and tool access
|
||||
|
||||
## Production Checklist
|
||||
|
||||
- [ ] HTTPS configured via reverse proxy
|
||||
- [ ] `AUTH_TOKEN` set and secure
|
||||
- [ ] Secrets stored in secrets manager (not `.env`)
|
||||
- [ ] Health checks configured
|
||||
- [ ] Monitoring and alerting set up
|
||||
- [ ] Logs aggregated and retained
|
||||
- [ ] Firewall rules configured
|
||||
- [ ] Rate limiting enabled
|
||||
- [ ] Resource limits set
|
||||
- [ ] Backup strategy in place
|
||||
- [ ] Disaster recovery plan documented
|
||||
- [ ] Security updates scheduled
|
||||
- [ ] Token rotation process defined
|
||||
|
||||
---
|
||||
|
||||
**For questions or issues, please open an issue on the [GitHub repository](https://github.com/lmiranda/gitea-mcp-remote/issues).**
|
||||
487
README.md
487
README.md
@@ -1,32 +1,80 @@
|
||||
# Gitea MCP Server
|
||||
# Gitea HTTP MCP Wrapper
|
||||
|
||||
A Model Context Protocol (MCP) server that enables AI assistants like Claude to interact with Gitea repositories through its API. This server provides tools for managing issues, labels, and milestones in your Gitea instance.
|
||||
An HTTP transport wrapper around the official Gitea MCP server that enables AI assistants like Claude Desktop to interact with Gitea repositories via HTTP. This wrapper provides authentication, tool filtering, and HTTP transport while delegating Gitea operations to the official `gitea-mcp-server`.
|
||||
|
||||
## Architecture
|
||||
|
||||
This is NOT a standalone MCP server. It's an HTTP wrapper that:
|
||||
1. Wraps the official `gitea-mcp-server` (stdio transport)
|
||||
2. Provides HTTP transport for Claude Desktop compatibility
|
||||
3. Adds Bearer token authentication
|
||||
4. Filters tools for Claude Desktop compatibility
|
||||
5. Proxies requests between HTTP and stdio transport
|
||||
|
||||
```
|
||||
Claude Desktop (HTTP) → HTTP Wrapper → Gitea MCP Server (stdio) → Gitea API
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **Issue Operations**: List, get, create, and update issues with full support for labels, milestones, and assignees
|
||||
- **Label Management**: List and create labels with custom colors and descriptions
|
||||
- **Milestone Management**: List and create milestones with due dates and descriptions
|
||||
- **Async API**: Built on modern async Python for efficient operations
|
||||
- **Type Safety**: Full type hints for better IDE support and code quality
|
||||
- **HTTP Transport**: Exposes MCP server via HTTP for Claude Desktop
|
||||
- **Authentication**: Optional Bearer token authentication
|
||||
- **Tool Filtering**: Enable/disable specific tools for compatibility
|
||||
- **Docker Deployment**: Production-ready containerization
|
||||
- **Health Checks**: Monitoring endpoints (`/health`, `/healthz`, `/ping`)
|
||||
- **Async Architecture**: Built on Starlette and uvicorn
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python >= 3.10
|
||||
- Official `gitea-mcp-server` package (auto-installed as dependency)
|
||||
- Gitea instance with API access
|
||||
- Gitea API token with appropriate permissions
|
||||
|
||||
## Quick Start with Docker
|
||||
|
||||
The easiest way to deploy is using Docker Compose:
|
||||
|
||||
```bash
|
||||
# 1. Clone the repository
|
||||
git clone https://github.com/lmiranda/gitea-mcp-remote.git
|
||||
cd gitea-mcp-remote
|
||||
|
||||
# 2. Create .env file from template
|
||||
cp .env.docker.example .env
|
||||
|
||||
# 3. Edit .env with your Gitea credentials
|
||||
nano .env
|
||||
|
||||
# 4. Start the server
|
||||
docker-compose up -d
|
||||
|
||||
# 5. Check health
|
||||
curl http://localhost:8000/health
|
||||
```
|
||||
|
||||
The server will be available at `http://localhost:8000`.
|
||||
|
||||
See [DEPLOYMENT.md](DEPLOYMENT.md) for detailed deployment instructions.
|
||||
|
||||
## Installation
|
||||
|
||||
### From Source
|
||||
### Option 1: Docker (Recommended)
|
||||
|
||||
See [Quick Start](#quick-start-with-docker) above or [DEPLOYMENT.md](DEPLOYMENT.md).
|
||||
|
||||
### Option 2: From Source
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/lmiranda/gitea-mcp-remote.git
|
||||
cd gitea-mcp-remote
|
||||
|
||||
# Install the package
|
||||
# Install the wrapper and its dependencies (including gitea-mcp-server)
|
||||
pip install -e .
|
||||
|
||||
# Or use requirements.txt
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### For Development
|
||||
@@ -39,32 +87,109 @@ pip install -e ".[dev]"
|
||||
|
||||
## Configuration
|
||||
|
||||
The server requires two environment variables to connect to your Gitea instance:
|
||||
The wrapper uses environment variables or a `.env` file for configuration.
|
||||
|
||||
- `GITEA_API_URL`: Base URL of your Gitea instance (e.g., `https://gitea.example.com/api/v1`)
|
||||
- `GITEA_API_TOKEN`: Personal access token for authentication
|
||||
|
||||
### Creating a .env File
|
||||
|
||||
Create a `.env` file in your project directory:
|
||||
### Required Configuration
|
||||
|
||||
```bash
|
||||
GITEA_API_URL=https://gitea.example.com/api/v1
|
||||
GITEA_API_TOKEN=your_gitea_token_here
|
||||
# Gitea Instance
|
||||
GITEA_URL=https://gitea.example.com
|
||||
GITEA_TOKEN=your_gitea_api_token_here
|
||||
GITEA_OWNER=your_username_or_org
|
||||
GITEA_REPO=your_repo_name
|
||||
|
||||
# HTTP Server
|
||||
HTTP_HOST=127.0.0.1 # Use 0.0.0.0 in Docker
|
||||
HTTP_PORT=8000
|
||||
```
|
||||
|
||||
### Optional Configuration
|
||||
|
||||
```bash
|
||||
# Bearer Authentication (optional but recommended)
|
||||
AUTH_TOKEN=your_secret_bearer_token
|
||||
|
||||
# Tool Filtering (optional)
|
||||
ENABLED_TOOLS=list_issues,create_issue,update_issue # Whitelist mode
|
||||
# OR
|
||||
DISABLED_TOOLS=delete_issue,close_milestone # Blacklist mode
|
||||
```
|
||||
|
||||
### Getting a Gitea API Token
|
||||
|
||||
1. Log into your Gitea instance
|
||||
2. Navigate to Settings > Applications
|
||||
3. Under "Generate New Token", enter a name (e.g., "MCP Server")
|
||||
3. Under "Generate New Token", enter a name (e.g., "MCP Wrapper")
|
||||
4. Select appropriate permissions (minimum: read/write for repositories)
|
||||
5. Click "Generate Token" and copy the token
|
||||
6. Add the token to your `.env` file
|
||||
|
||||
## Usage with Claude Desktop
|
||||
## Usage
|
||||
|
||||
Add this configuration to your Claude Desktop config file:
|
||||
### Running the Server
|
||||
|
||||
#### With Docker
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
#### From Source
|
||||
|
||||
```bash
|
||||
# Create .env file from template
|
||||
cp .env.example .env
|
||||
# Edit .env with your configuration
|
||||
nano .env
|
||||
|
||||
# Run the server
|
||||
gitea-http-wrapper
|
||||
```
|
||||
|
||||
The server will start on the configured host/port (default: `http://127.0.0.1:8000`).
|
||||
|
||||
### HTTP Endpoints
|
||||
|
||||
#### Health Check
|
||||
```bash
|
||||
GET /health
|
||||
GET /healthz
|
||||
GET /ping
|
||||
|
||||
Response: {"status": "healthy"}
|
||||
```
|
||||
|
||||
#### List Tools
|
||||
```bash
|
||||
POST /tools/list
|
||||
|
||||
Response: {
|
||||
"tools": [
|
||||
{"name": "list_issues", "description": "...", "inputSchema": {...}},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Call Tool
|
||||
```bash
|
||||
POST /tools/call
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer YOUR_TOKEN # If auth enabled
|
||||
|
||||
{
|
||||
"name": "list_issues",
|
||||
"arguments": {
|
||||
"owner": "myorg",
|
||||
"repo": "myrepo",
|
||||
"state": "open"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### With Claude Desktop
|
||||
|
||||
Configure Claude Desktop to use the HTTP wrapper:
|
||||
|
||||
**Location:**
|
||||
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
||||
@@ -77,48 +202,9 @@ Add this configuration to your Claude Desktop config file:
|
||||
{
|
||||
"mcpServers": {
|
||||
"gitea": {
|
||||
"command": "python",
|
||||
"args": ["-m", "gitea_mcp.server"],
|
||||
"env": {
|
||||
"GITEA_API_URL": "https://gitea.example.com/api/v1",
|
||||
"GITEA_API_TOKEN": "your_gitea_token_here"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or, if you prefer using a .env file:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"gitea": {
|
||||
"command": "python",
|
||||
"args": ["-m", "gitea_mcp.server"],
|
||||
"cwd": "/path/to/gitea-mcp-remote"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage with Claude Code
|
||||
|
||||
Add to your MCP settings file:
|
||||
|
||||
**Location:** `~/.config/claude-code/mcp.json` (or your configured MCP settings path)
|
||||
|
||||
**Configuration:**
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"gitea": {
|
||||
"command": "python",
|
||||
"args": ["-m", "gitea_mcp.server"],
|
||||
"env": {
|
||||
"GITEA_API_URL": "https://gitea.example.com/api/v1",
|
||||
"GITEA_API_TOKEN": "your_gitea_token_here"
|
||||
"url": "http://localhost:8000",
|
||||
"headers": {
|
||||
"Authorization": "Bearer YOUR_TOKEN"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,170 +213,13 @@ Add to your MCP settings file:
|
||||
|
||||
## Available Tools
|
||||
|
||||
### Issue Tools
|
||||
The wrapper exposes all tools from the official `gitea-mcp-server`. See the [official Gitea MCP documentation](https://github.com/modelcontextprotocol/servers/tree/main/src/gitea) for the complete list of available tools:
|
||||
|
||||
#### gitea_list_issues
|
||||
- **Issues**: List, get, create, update issues
|
||||
- **Labels**: List, create labels
|
||||
- **Milestones**: List, create milestones
|
||||
|
||||
List issues in a repository with optional filters.
|
||||
|
||||
**Parameters:**
|
||||
- `owner` (required): Repository owner (username or organization)
|
||||
- `repo` (required): Repository name
|
||||
- `state` (optional): Filter by state - `open`, `closed`, or `all` (default: `open`)
|
||||
- `labels` (optional): Comma-separated list of label names to filter by
|
||||
- `milestone` (optional): Milestone name to filter by
|
||||
- `page` (optional): Page number for pagination (default: 1)
|
||||
- `limit` (optional): Number of issues per page (default: 30)
|
||||
|
||||
**Example:**
|
||||
```
|
||||
List all open issues in myorg/myrepo
|
||||
```
|
||||
|
||||
#### gitea_get_issue
|
||||
|
||||
Get details of a specific issue by number.
|
||||
|
||||
**Parameters:**
|
||||
- `owner` (required): Repository owner
|
||||
- `repo` (required): Repository name
|
||||
- `index` (required): Issue number
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Get details of issue #42 in myorg/myrepo
|
||||
```
|
||||
|
||||
#### gitea_create_issue
|
||||
|
||||
Create a new issue in a repository.
|
||||
|
||||
**Parameters:**
|
||||
- `owner` (required): Repository owner
|
||||
- `repo` (required): Repository name
|
||||
- `title` (required): Issue title
|
||||
- `body` (optional): Issue description/body
|
||||
- `labels` (optional): Array of label IDs to assign
|
||||
- `milestone` (optional): Milestone ID to assign
|
||||
- `assignees` (optional): Array of usernames to assign
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Create an issue in myorg/myrepo with title "Bug: Login fails" and body "Users cannot log in with special characters in password"
|
||||
```
|
||||
|
||||
#### gitea_update_issue
|
||||
|
||||
Update an existing issue.
|
||||
|
||||
**Parameters:**
|
||||
- `owner` (required): Repository owner
|
||||
- `repo` (required): Repository name
|
||||
- `index` (required): Issue number
|
||||
- `title` (optional): New issue title
|
||||
- `body` (optional): New issue body
|
||||
- `state` (optional): Issue state - `open` or `closed`
|
||||
- `labels` (optional): Array of label IDs (replaces existing)
|
||||
- `milestone` (optional): Milestone ID to assign
|
||||
- `assignees` (optional): Array of usernames (replaces existing)
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Close issue #42 in myorg/myrepo
|
||||
```
|
||||
|
||||
### Label Tools
|
||||
|
||||
#### gitea_list_labels
|
||||
|
||||
List all labels in a repository.
|
||||
|
||||
**Parameters:**
|
||||
- `owner` (required): Repository owner
|
||||
- `repo` (required): Repository name
|
||||
|
||||
**Example:**
|
||||
```
|
||||
List all labels in myorg/myrepo
|
||||
```
|
||||
|
||||
#### gitea_create_label
|
||||
|
||||
Create a new label in a repository.
|
||||
|
||||
**Parameters:**
|
||||
- `owner` (required): Repository owner
|
||||
- `repo` (required): Repository name
|
||||
- `name` (required): Label name
|
||||
- `color` (required): Label color (hex without #, e.g., `ff0000` for red)
|
||||
- `description` (optional): Label description
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Create a label "bug" with red color (ff0000) in myorg/myrepo
|
||||
```
|
||||
|
||||
### Milestone Tools
|
||||
|
||||
#### gitea_list_milestones
|
||||
|
||||
List milestones in a repository.
|
||||
|
||||
**Parameters:**
|
||||
- `owner` (required): Repository owner
|
||||
- `repo` (required): Repository name
|
||||
- `state` (optional): Filter by state - `open`, `closed`, or `all` (default: `open`)
|
||||
|
||||
**Example:**
|
||||
```
|
||||
List all milestones in myorg/myrepo
|
||||
```
|
||||
|
||||
#### gitea_create_milestone
|
||||
|
||||
Create a new milestone in a repository.
|
||||
|
||||
**Parameters:**
|
||||
- `owner` (required): Repository owner
|
||||
- `repo` (required): Repository name
|
||||
- `title` (required): Milestone title
|
||||
- `description` (optional): Milestone description
|
||||
- `due_on` (optional): Due date in ISO 8601 format (e.g., `2024-12-31T23:59:59Z`)
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Create a milestone "v1.0 Release" with due date 2024-12-31 in myorg/myrepo
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Core Components
|
||||
|
||||
#### GiteaClient
|
||||
|
||||
HTTP client for Gitea API interactions.
|
||||
|
||||
**Methods:**
|
||||
- `get(endpoint, params)`: GET request
|
||||
- `post(endpoint, json)`: POST request
|
||||
- `patch(endpoint, json)`: PATCH request
|
||||
|
||||
#### AuthConfig
|
||||
|
||||
Configuration manager for API authentication.
|
||||
|
||||
**Environment Variables:**
|
||||
- `GITEA_API_URL`: Gitea API base URL
|
||||
- `GITEA_API_TOKEN`: Authentication token
|
||||
|
||||
**Methods:**
|
||||
- `get_auth_headers()`: Returns authentication headers
|
||||
|
||||
### Tool Modules
|
||||
|
||||
- `gitea_mcp.tools.issues`: Issue operation tools and handlers
|
||||
- `gitea_mcp.tools.labels`: Label operation tools and handlers
|
||||
- `gitea_mcp.tools.milestones`: Milestone operation tools and handlers
|
||||
Tool availability can be controlled via the `ENABLED_TOOLS` or `DISABLED_TOOLS` configuration.
|
||||
|
||||
## Development
|
||||
|
||||
@@ -304,7 +233,14 @@ pip install -e ".[dev]"
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
pytest
|
||||
|
||||
# Run with coverage
|
||||
pytest --cov=gitea_http_wrapper
|
||||
|
||||
# Run specific test file
|
||||
pytest src/gitea_http_wrapper/tests/test_config.py
|
||||
```
|
||||
|
||||
### Project Structure
|
||||
@@ -312,28 +248,44 @@ pytest
|
||||
```
|
||||
gitea-mcp-remote/
|
||||
├── src/
|
||||
│ └── gitea_mcp/
|
||||
│ └── gitea_http_wrapper/
|
||||
│ ├── __init__.py
|
||||
│ ├── server.py # MCP server implementation
|
||||
│ ├── auth.py # Authentication config
|
||||
│ ├── client.py # Gitea API client
|
||||
│ └── tools/ # Tool implementations
|
||||
│ ├── __init__.py
|
||||
│ ├── issues.py # Issue tools
|
||||
│ ├── labels.py # Label tools
|
||||
│ └── milestones.py # Milestone tools
|
||||
├── tests/ # Test suite
|
||||
├── pyproject.toml # Project configuration
|
||||
└── README.md # This file
|
||||
│ ├── server.py # Main HTTP server
|
||||
│ ├── config/
|
||||
│ │ ├── __init__.py
|
||||
│ │ └── settings.py # Configuration loader
|
||||
│ ├── middleware/
|
||||
│ │ ├── __init__.py
|
||||
│ │ └── auth.py # HTTP authentication
|
||||
│ ├── filtering/
|
||||
│ │ ├── __init__.py
|
||||
│ │ └── filter.py # Tool filtering
|
||||
│ └── tests/ # Test suite
|
||||
│ ├── conftest.py
|
||||
│ ├── test_config.py
|
||||
│ ├── test_filtering.py
|
||||
│ └── test_middleware.py
|
||||
├── Dockerfile # Docker image
|
||||
├── docker-compose.yml # Docker orchestration
|
||||
├── pyproject.toml # Project config
|
||||
├── requirements.txt # Dependencies
|
||||
├── .env.example # Config template
|
||||
├── .env.docker.example # Docker config template
|
||||
├── README.md # This file
|
||||
└── DEPLOYMENT.md # Deployment guide
|
||||
```
|
||||
|
||||
### Code Quality
|
||||
## Deployment
|
||||
|
||||
This project uses:
|
||||
- Type hints throughout the codebase
|
||||
- Async/await for all I/O operations
|
||||
- Comprehensive error handling
|
||||
- Structured logging
|
||||
For production deployment instructions, see [DEPLOYMENT.md](DEPLOYMENT.md), which covers:
|
||||
|
||||
- Docker deployment
|
||||
- Docker Compose orchestration
|
||||
- Security best practices
|
||||
- Monitoring and health checks
|
||||
- Scaling considerations
|
||||
- Cloud deployment (AWS, GCP, Azure)
|
||||
- Kubernetes deployment
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -341,27 +293,53 @@ This project uses:
|
||||
|
||||
If you receive authentication errors:
|
||||
|
||||
1. Verify your `GITEA_API_TOKEN` is correct
|
||||
1. Verify your `GITEA_TOKEN` is correct
|
||||
2. Check that the token has appropriate permissions
|
||||
3. Ensure your `GITEA_API_URL` includes `/api/v1` at the end
|
||||
4. Verify the Gitea instance is accessible from your network
|
||||
3. Ensure your `GITEA_URL` does NOT include `/api/v1` (wrapper adds it)
|
||||
4. Verify the Gitea instance is accessible from the wrapper's network
|
||||
|
||||
### HTTP 401/403 Errors
|
||||
|
||||
If Claude Desktop receives 401 or 403 errors:
|
||||
|
||||
1. Check that `AUTH_TOKEN` is configured (if authentication is enabled)
|
||||
2. Verify Claude Desktop config includes the correct `Authorization` header
|
||||
3. Check server logs for authentication failures
|
||||
|
||||
### Connection Errors
|
||||
|
||||
If you cannot connect to Gitea:
|
||||
If the wrapper cannot connect to Gitea:
|
||||
|
||||
1. Check that `GITEA_API_URL` is correct and accessible
|
||||
1. Check that `GITEA_URL` is correct and accessible
|
||||
2. Verify network connectivity to the Gitea instance
|
||||
3. Check for firewalls or proxies blocking the connection
|
||||
4. In Docker: Ensure the container can reach the Gitea host
|
||||
|
||||
### Tool Not Found
|
||||
### gitea-mcp-server Not Found
|
||||
|
||||
If Claude cannot find the tools:
|
||||
If the wrapper fails to start with "gitea-mcp-server not found":
|
||||
|
||||
1. Restart Claude Desktop/Code after updating the configuration
|
||||
2. Verify the configuration file syntax is valid JSON
|
||||
3. Check that Python is in your PATH
|
||||
4. Ensure the package is properly installed (`pip list | grep gitea-mcp`)
|
||||
1. Verify `gitea-mcp-server` is installed: `pip list | grep gitea-mcp`
|
||||
2. Install it manually: `pip install gitea-mcp-server`
|
||||
3. In Docker: Rebuild the image
|
||||
|
||||
### Tool Filtering Not Working
|
||||
|
||||
If tool filtering is not applied:
|
||||
|
||||
1. Check `.env` file syntax (no spaces around `=`)
|
||||
2. Verify comma-separated list format
|
||||
3. Check server logs for filter configuration
|
||||
4. Query `POST /tools/list` to see filtered tools
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- **Always use HTTPS** in production (configure reverse proxy)
|
||||
- **Set AUTH_TOKEN** to secure the HTTP endpoint
|
||||
- **Rotate tokens regularly** (both Gitea token and auth token)
|
||||
- **Use secrets management** (not .env files) in production
|
||||
- **Limit network exposure** (firewall, VPN, or private network)
|
||||
- **Monitor access logs** for suspicious activity
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -383,4 +361,5 @@ Leo Miranda
|
||||
|
||||
- Repository: https://github.com/lmiranda/gitea-mcp-remote
|
||||
- Issues: https://github.com/lmiranda/gitea-mcp-remote/issues
|
||||
- Official Gitea MCP Server: https://github.com/modelcontextprotocol/servers/tree/main/src/gitea
|
||||
- MCP Documentation: https://modelcontextprotocol.io
|
||||
|
||||
Reference in New Issue
Block a user