Skip to content

Security: MimoJanra/TestOpsMCP

docs/SECURITY.md

Security Guide

Security considerations and best practices for Allure MCP Server.

Table of Contents

Authentication

Stdio Mode (Local Development)

Security Model: Subprocess with inherited privileges

  • No auth: runs as your user, no network exposure
  • Suitable only for local development and Claude Desktop
  • No credentials transmitted over network
  • ⚠️ Never use stdio mode with untrusted code

HTTP Mode (Team/Server)

Always set MCP_AUTH_TOKEN in production.

# Generate a strong random token
openssl rand -base64 32

# Export to .env
MCP_AUTH_TOKEN=your_generated_token_here

Clients must include the token:

curl -H "Authorization: Bearer $MCP_AUTH_TOKEN" http://localhost:3000/sse

The token is checked on:

  • GET /sse — SSE stream endpoint
  • POST /messages — Message submission endpoint

Note: Token is case-sensitive and checked with Bearer scheme.


Network Security

Use HTTPS in Production

Never expose HTTP over the internet. Always use HTTPS.

Option 1: Reverse Proxy with TLS

Nginx example:

server {
    listen 443 ssl http2;
    server_name allure-mcp.example.com;

    ssl_certificate /etc/letsencrypt/live/allure-mcp.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/allure-mcp.example.com/privkey.pem;

    # TLS hardening
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Option 2: Caddy (Auto HTTPS)

allure-mcp.example.com {
    reverse_proxy localhost:3000
}

Caddy automatically obtains and renews HTTPS certificates.

Option 3: Kubernetes with TLS

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: allure-mcp
spec:
  tls:
  - hosts:
    - allure-mcp.example.com
    secretName: allure-mcp-tls
  rules:
  - host: allure-mcp.example.com
    http:
      paths:
      - path: /
        backend:
          service:
            name: allure-mcp
            port:
              number: 3000

Restrict CORS

Default CORS_ALLOWED_ORIGIN=* allows any site to call your server.

Set to specific domains:

# Production
CORS_ALLOWED_ORIGIN=https://claude.ai

# Internal team only
CORS_ALLOWED_ORIGIN=https://allure-mcp.internal.example.com

In Nginx:

location / {
    add_header 'Access-Control-Allow-Origin' 'https://claude.ai' always;
    add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'Content-Type,Authorization' always;
}

Rate Limiting

Nginx:

limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

location / {
    limit_req zone=api_limit burst=20 nodelay;
    proxy_pass http://localhost:3000;
}

Caddy:

allure-mcp.example.com {
    rate_limit 10r/s burst=20
    reverse_proxy localhost:3000
}

Firewall Rules

Allow only trusted IPs:

# Nginx
location / {
    allow 10.0.0.0/8;     # Internal network
    allow 203.0.113.0/24;  # Team office
    deny all;
}

Or at firewall level:

# iptables
sudo iptables -A INPUT -p tcp --dport 3000 -s 10.0.0.0/8 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 3000 -j DROP

Secret Management

Never Commit .env

.gitignore already contains:

.env
.env.local
.env.*.secret

Verify before committing:

git status
# Should NOT show .env

git diff --cached | grep -i "token\|password\|secret"
# Should return nothing

Store Secrets Securely

Development:

  • Use .env (local only)
  • Never commit to git
  • Limit file permissions: chmod 600 .env

Team/Production:

  • Use secret manager: Vault, AWS Secrets Manager, Azure Key Vault
  • Example with Vault:
vault write secret/allure-mcp \
  base_url="https://allure.example.com" \
  token="$(openssl rand -base64 32)"
  • Read in startup script:
export ALLURE_BASE_URL=$(vault kv get -field=base_url secret/allure-mcp)
export ALLURE_TOKEN=$(vault kv get -field=token secret/allure-mcp)
./bin/server --http

Kubernetes:

apiVersion: v1
kind: Secret
metadata:
  name: allure-credentials
type: Opaque
stringData:
  ALLURE_BASE_URL: https://allure.example.com
  ALLURE_TOKEN: your_token_here
  MCP_AUTH_TOKEN: your_mcp_secret

Mount in pod:

env:
- name: ALLURE_TOKEN
  valueFrom:
    secretKeyRef:
      name: allure-credentials
      key: ALLURE_TOKEN

Rotate Credentials

Allure API Token:

  1. Generate new token in Allure UI
  2. Update ALLURE_TOKEN in secret manager
  3. Restart server with new token
  4. Revoke old token in Allure UI

MCP Auth Token:

  1. Generate new token: openssl rand -base64 32
  2. Update MCP_AUTH_TOKEN in .env or secret manager
  3. Restart server
  4. Notify team of new token
  5. Clients must update their config

Destructive Operation Confirmation

delete_test_case and bulk_delete_test_cases require explicit user confirmation before executing.

How it works

When a delete tool is called over an HTTP/SSE session, the server sends an elicitation request (elicitation/create) to the client. The client displays a confirmation dialog; the user must click Accept before the deletion proceeds. If the user rejects or cancels, the tool returns {"cancelled": true} without touching any data.

Claude → server: tools/call delete_test_case {test_case_id: 42}
server → client: elicitation/create {message: "Permanently delete test case #42?..."}
user   → client: [clicks Accept]
client → server: JSON-RPC response {id: ..., result: {action: "accept"}}
server → Allure: DELETE /api/testcase/42
server → Claude: {status: "deleted"}

Transport requirements

Transport Confirmation Notes
HTTP + SSE (/sse, /messages) ✓ Elicitation dialog shown Full support
Streamable HTTP (/mcp) ✓ Elicitation dialog shown Full support
Stdio ✗ Returns error Interactive session required for destructive ops

Stdio note: When running in stdio mode (e.g. a Claude Desktop local binary), there is no interactive session capable of elicitation. Delete tools return an error: "deletion requires user confirmation but no interactive session is available". Use the HTTP transport for deployments where destructive operations are needed.


Compliance

Data Privacy

The server:

  • ✓ Does not store user data
  • ✓ Does not log API tokens
  • ✓ Does not persist launch history
  • ✓ Proxies requests only to Allure TestOps

All state is in Allure TestOps. This server is stateless.

⚠️ Logs may contain launch names/project IDs — handle accordingly if sensitive.

Audit Logging

Enable structured logging for audit trails:

LOG_LEVEL=INFO
# Server logs all tool calls and errors

Example log:

{"level":"INFO","msg":"Tool called","tool":"run_allure_launch","project_id":1,"timestamp":"2025-01-15T10:30:00Z","clientIP":"10.0.0.1"}

Send logs to centralized system:

  • ELK Stack (Elasticsearch + Kibana + Logstash)
  • Datadog / New Relic / Splunk
  • Loki + Grafana

Compliance Standards

SOC2:

  • ✓ Encrypted secrets (use secret manager)
  • ✓ Access logs with audit trail
  • ✓ Rate limiting prevents abuse
  • ✓ TLS/HTTPS enforced

GDPR:

  • ✓ No personal data stored
  • ✓ Stateless design
  • ✓ Can be deleted without data migration

HIPAA (for healthcare):

  • ✓ Encrypt at rest (secret manager)
  • ✓ Encrypt in transit (HTTPS)
  • ✓ Access logs (centralized monitoring)
  • ✓ Run in VPC/private network

Security Checklist

Before Production Deployment

  • Authentication

    • MCP_AUTH_TOKEN is set to strong random value
    • Token is stored in secret manager (Vault, AWS Secrets Manager, etc.)
    • Token rotated monthly
  • Network

    • HTTPS/TLS enabled
    • Reverse proxy (Nginx, Caddy) configured
    • Firewall rules restrict access
    • CORS_ALLOWED_ORIGIN is specific (not *)
    • Rate limiting enabled
  • Secrets

    • .env not committed to git
    • Allure token stored in secret manager
    • MCP auth token stored in secret manager
    • File permissions: chmod 600 for .env
  • Monitoring

    • Structured JSON logging enabled
    • Logs sent to centralized system
    • Alerting configured for errors/failures
    • Access logs reviewed regularly
  • Infrastructure

    • Running as non-root user (UID 1000)
    • Read-only filesystem where possible
    • Resource limits set (CPU, memory)
    • Health checks configured
    • Backups documented (if applicable)
  • Updates

    • Go version is 1.26+
    • Dependencies up-to-date (go mod tidy)
    • Security advisories checked (go list -u -m all)
    • Update process documented
  • Documentation

    • Security policy documented
    • Incident response plan in place
    • Credential rotation schedule documented
    • Disaster recovery plan documented

Before Each Deployment

  • No secrets in code or commit history
  • All tests pass (make check)
  • Linting passes (make lint)
  • Build is reproducible (make clean && make build)
  • CHANGELOG updated
  • Security fixes highlighted

Incident Response

If API Token Leaks

  1. Immediately revoke token in Allure UI
  2. Generate new token
  3. Update secret manager with new token
  4. Restart all server instances
  5. Review logs for unauthorized access
  6. Document timeline and root cause

If MCP Auth Token Leaks

  1. Generate new token: openssl rand -base64 32
  2. Update .env or secret manager
  3. Restart server
  4. Notify all team members
  5. Force clients to update config
  6. Review logs for unauthorized access

If Server Compromised

  1. Stop the server immediately
  2. Revoke both Allure token and MCP auth token
  3. Review all logs for unauthorized tool calls
  4. Redeploy clean version
  5. Update all credentials
  6. Notify stakeholders
  7. Document incident

Reporting Security Issues

Do NOT open public GitHub issues for security vulnerabilities.

Email security concerns to: mimojanra@gmail.com

Include:

  • Description of vulnerability
  • Steps to reproduce
  • Potential impact
  • Proposed fix (if any)

We will:

  1. Acknowledge receipt within 24 hours
  2. Assess severity
  3. Prepare patch (if applicable)
  4. Coordinate disclosure with you
  5. Release patched version
  6. Credit you (with permission)

Destructive Operation Protection (Elicitation)

Permanently destructive operations (delete_test_case, bulk_delete_test_cases) use MCP elicitation to request explicit user confirmation before proceeding:

  1. When the tool is called, the server sends an elicitation/create notification via SSE.
  2. The client (Claude Desktop / claude.ai) displays a confirmation dialog to the user.
  3. If the user accepts, the deletion proceeds. If the user rejects or cancels, the tool returns {"cancelled": true} without touching any data.

This prevents accidental mass deletion and provides an audit trail via the audit log.

Note: Elicitation requires a client that supports it. If the client does not respond within 5 minutes, the server returns a timeout error and does not delete.

Server Stability (Panic Recovery)

All JSON-RPC request handlers are wrapped in a panic recovery middleware. If a handler panics:

  • The panic is caught and logged with the full stack trace at ERROR level.
  • The client receives a JSON-RPC internal error (-32603) instead of a connection drop.
  • The server continues running and serving other requests.

This prevents a single bad request from crashing a shared team server.

Additional Resources


Keep security updated. Rotate credentials. Monitor logs. 🔐

There aren't any published security advisories