Sentinel CI Architecture¶
Overview¶
Sentinel CI is a multi-platform CI/CD intelligence layer built using the Model Context Protocol (MCP). It provides a unified interface for AI agents to interact with various CI/CD platforms (Jenkins, GitHub Actions, GitLab CI, and generic CI systems).
System Architecture¶
┌─────────────────────────────────────────────────────────────┐
│ AI Agent / Client │
│ (Claude, GPT, Custom AI) │
└───────────────────────────┬─────────────────────────────────┘
│
│ MCP Protocol (stdio/HTTP)
│
┌───────────────────────────▼─────────────────────────────────┐
│ Sentinel CI Server │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ MCP Server (FastMCP) │ │
│ │ - health_check() - get_failed_stages() │ │
│ │ - list_jobs() - get_failed_tests() │ │
│ │ - get_build_summary() - get_log_excerpt() │ │
│ │ - get_metrics() - clear_cache() │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────┴────────────────────────────┐ │
│ │ Platform Router │ │
│ │ (Routes requests to appropriate client) │ │
│ └────────────────────────┬─────────────────────────────┘ │
│ │ │
│ ┌──────────────────┼──────────────────┐ │
│ │ │ │ │
│ ┌──────▼──────┐ ┌────────▼─────┐ ┌─────────▼────┐ │
│ │ Jenkins │ │GitHub Actions│ │ GitLab CI │ │
│ │ Client │ │ Client │ │ Client │ │
│ └──────┬──────┘ └───────┬──────┘ └───────┬──────┘ │
│ │ │ │ │
│ ┌──────▼─────────────────▼─────────────────▼──────────┐ │
│ │ Shared Components │ │
│ │ ┌────────┐ ┌──────────┐ ┌─────────────────┐ │ │
│ │ │ Cache │ │ Redactor │ │ Metrics │ │ │
│ │ │(TTL, │ │(Secret │ │(Prometheus) │ │ │
│ │ │ LRU) │ │patterns) │ │ │ │ │
│ │ └────────┘ └──────────┘ └─────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└────────────────────────────┬────────────────────────────────┘
│
│ REST APIs
│
┌───────────────────┼───────────────────┐
│ │ │
┌────▼────┐ ┌───────▼─────┐ ┌──────▼───┐
│ Jenkins │ │ GitHub │ │ GitLab │
│ API │ │ Actions API │ │ CI API │
└─────────┘ └─────────────┘ └──────────┘
Component Details¶
1. MCP Server Layer¶
Location: sentinel_ci/server.py
Responsibilities: - Expose MCP tools for AI agents - Handle tool invocations - Route requests to appropriate platform client - Coordinate caching and metrics
Key Tools:
@app.tool()
def health_check() -> dict:
"""Check connectivity to CI platform"""
@app.tool()
def list_jobs(path: str = None) -> dict:
"""List all jobs/workflows"""
@app.tool()
def get_build_summary(job: str, build_id: str) -> dict:
"""Get summary of a specific build"""
@app.tool()
def get_failed_stages(job: str, build_id: str) -> dict:
"""Get failed stages/steps"""
@app.tool()
def get_failed_tests(job: str, build_id: str) -> dict:
"""Get failed test details"""
@app.tool()
def get_log_excerpt(job: str, build_id: str, stage: str, lines: int) -> dict:
"""Get relevant log excerpts"""
@app.tool()
def get_metrics() -> dict:
"""Get system metrics"""
@app.tool()
def clear_cache() -> dict:
"""Clear the cache"""
Configuration:
# Select platform via environment variable
CI_PLATFORM = os.getenv('CI_PLATFORM', 'jenkins')
# Platform-specific credentials
JENKINS_URL = os.getenv('JENKINS_URL')
JENKINS_TOKEN = os.getenv('JENKINS_TOKEN')
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')
GITLAB_TOKEN = os.getenv('GITLAB_TOKEN')
2. Platform Clients¶
All platform clients implement the AbstractCIClient interface:
class AbstractCIClient(ABC):
@abstractmethod
def health_check(self) -> dict:
pass
@abstractmethod
def list_jobs(self, path=None) -> dict:
pass
@abstractmethod
def get_build_summary(self, job: str, build_id: str) -> dict:
pass
# ... other methods
Jenkins Client¶
Location: mcps/jenkins/client.py
Features: - Classic and Pipeline job support - Blue Ocean API integration - wfapi plugin for pipeline details - JUnit test result parsing
API Endpoints Used:
- /api/json - Job listing
- /job/{name}/{build}/api/json - Build details
- /job/{name}/{build}/wfapi/describe - Pipeline stages
- /job/{name}/{build}/testReport/api/json - Test results
- /job/{name}/{build}/consoleText - Build logs
Status Mapping:
color_map = {
'blue': 'SUCCESS',
'red': 'FAILURE',
'yellow': 'UNSTABLE',
'aborted': 'ABORTED',
'notbuilt': 'NOT_BUILT',
}
GitHub Actions Client¶
Location: mcps/github_actions/client.py
Features: - Workflow runs - Job details - Step information - Artifact access
API Endpoints Used:
- GET /repos/{owner}/{repo}/actions/runs - List runs
- GET /repos/{owner}/{repo}/actions/runs/{id} - Run details
- GET /repos/{owner}/{repo}/actions/runs/{id}/jobs - Job details
- GET /repos/{owner}/{repo}/actions/runs/{id}/logs - Logs
Authentication:
GitLab CI Client¶
Location: mcps/gitlab_ci/client.py
Features: - Pipeline jobs - Stage details - Test reports (native support) - MR pipeline tracking
API Endpoints Used:
- GET /api/v4/projects/{id}/pipelines - List pipelines
- GET /api/v4/projects/{id}/pipelines/{id}/jobs - Jobs
- GET /api/v4/projects/{id}/pipelines/{id}/test_report - Tests
- GET /api/v4/projects/{id}/jobs/{id}/trace - Logs
Authentication:
3. Shared Components¶
Caching Layer¶
Location: shared/caching/cache.py
Features: - TTL-based expiration - LRU eviction - Thread-safe operations - Cache statistics
Implementation:
class SimpleCache:
def __init__(self, ttl_seconds: int, max_size: int):
self._cache = {}
self._ttl = ttl_seconds
self._max_size = max_size
self._lock = threading.Lock()
def get(self, key: str):
# Check expiration, return value
def set(self, key: str, value):
# Store with timestamp, enforce max_size
Cache TTLs: - Health checks: 30 seconds - Job lists: 60 seconds - Build summaries: 120 seconds - Test results: 120 seconds
Secret Redaction¶
Location: shared/redaction/redactor.py
Features: - Pattern-based redaction - 12 built-in patterns - Configurable replacement text - Regex compilation
Patterns:
patterns = [
(r'api[_-]?key[=:]\s*["\']?([a-zA-Z0-9_-]+)', '[REDACTED]'),
(r'password[=:]\s*["\']?([^\s\'"]+)', '[REDACTED]'),
(r'token[=:]\s*["\']?([a-zA-Z0-9_.-]+)', '[REDACTED]'),
# ... 9 more patterns
]
Usage:
Metrics Collection¶
Location: shared/metrics/metrics.py
Features: - Prometheus format - Counter metrics - Histogram metrics - Percentile calculation
Metrics Tracked:
# Counters
- cache_hits_total
- cache_misses_total
- api_calls_total
- errors_total
# Histograms
- api_call_duration_seconds (P50, P95, P99)
- cache_operation_duration_seconds
Export Format:
# HELP cache_hits_total Total cache hits
# TYPE cache_hits_total counter
cache_hits_total 42
# HELP api_call_duration_seconds API call duration
# TYPE api_call_duration_seconds histogram
api_call_duration_seconds_bucket{le="0.5"} 10
api_call_duration_seconds_bucket{le="1.0"} 25
...
Data Flow¶
Example: Get Failed Tests¶
1. AI Agent requests: get_failed_tests("backend-service", "123")
↓
2. MCP Server receives request
↓
3. Check cache for key: "failed_tests:backend-service:123"
↓
4. Cache miss → Forward to platform client
↓
5. Platform client calls CI API (e.g., Jenkins /testReport)
↓
6. Parse API response, extract failed tests
↓
7. Redact secrets from test output
↓
8. Store result in cache (TTL: 120s)
↓
9. Record metrics (api_calls_total++, duration_histogram)
↓
10. Return formatted result to AI agent
Performance Characteristics¶
Latency Targets¶
- Cache hit: < 10ms
- Cache miss + API call: < 2s (P95)
- Health check: < 500ms
- Log excerpt: < 3s (depends on log size)
Caching Strategy¶
Cache keys format:
{operation}:{job}:{build_id}:{extra}
Examples:
- health_check:jenkins
- list_jobs:jenkins:path=/folder
- build_summary:backend-service:123
- failed_tests:frontend-app:456
Eviction policy: 1. TTL expiration (time-based) 2. LRU when max_size reached (capacity-based)
Resource Usage¶
Memory: - Base: ~50MB - Per cached entry: ~10KB - Max cache: ~100MB (1000 entries × 10KB × 10 platforms)
Network: - Health checks: 1 request/30s - Job list: 1 request/60s - Build details: 1 request per unique build (cached 120s)
Security Considerations¶
Authentication Flow¶
1. User provides credentials via environment variables
↓
2. Sentinel CI loads credentials on startup
↓
3. Never logs or exposes raw credentials
↓
4. Uses credentials to authenticate API calls
↓
5. Redacts any credentials from logs/output
Read-Only Operations¶
All operations are read-only: - ❌ Cannot trigger builds - ❌ Cannot modify configurations - ❌ Cannot delete jobs/builds - ✅ Only fetches existing data - ✅ Safe for production use
Audit Trail¶
# Every API call logged
logger.info(f"API call: {method} {endpoint} user={user}")
# Metrics recorded
metrics.increment('api_calls_total', labels={'platform': 'jenkins'})
# Cache operations tracked
metrics.record('cache_operation_duration_seconds', duration)
Extensibility¶
Adding a New Platform¶
-
Create client class:
-
Update server router:
-
Add configuration:
Adding a New Tool¶
-
Define tool in server:
-
Implement in abstract client:
-
Implement in each platform client:
Deployment Options¶
Standalone Server¶
Docker Container¶
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "-m", "sentinel_ci.server"]
Claude Desktop Integration¶
{
"mcpServers": {
"sentinel-ci": {
"command": "python",
"args": ["-m", "sentinel_ci.server"],
"env": {
"CI_PLATFORM": "jenkins",
"JENKINS_URL": "https://jenkins.example.com",
"JENKINS_TOKEN": "user:token"
}
}
}
}
Monitoring¶
Health Checks¶
# Check server health
curl http://localhost:8000/health
# Expected response
{
"status": "healthy",
"platform": "jenkins",
"cache_stats": {...},
"uptime_seconds": 3600
}
Metrics Endpoint¶
# Get Prometheus metrics
curl http://localhost:8000/metrics
# Integration with Prometheus
- job_name: 'sentinel-ci'
static_configs:
- targets: ['localhost:8000']
Future Architecture Enhancements¶
- Multi-platform aggregation:
- Query multiple platforms simultaneously
-
Unified dashboard across platforms
-
Webhook support:
- Real-time notifications
-
Event-driven updates
-
Advanced caching:
- Redis backend
- Distributed cache
-
Cache warming
-
Authentication middleware:
- OAuth integration
- API key management
-
Role-based access control
-
Batch operations:
- Bulk job queries
- Parallel API calls
- GraphQL endpoint