CI/CD Integration

Add TrustTrace security scanning to your deployment pipeline. Catch vulnerabilities before they reach production.

Requires Team plan or above for webhook notifications. API scanning works on all paid plans.


GitHub Actions

Add this workflow to scan your MCP server on every push or pull request:

name: TrustTrace Security Scan
on: [push, pull_request]

jobs:
  ai-security-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Scan MCP Server
        id: scan
        run: |
          # Submit scan
          RESULT=$(curl -s -X POST https://api.trusttrace.io/v1/scan/mcp \
            -H "Authorization: Bearer ${{ secrets.TRUSTTRACE_API_KEY }}" \
            -H "Content-Type: application/json" \
            -d '{"url": "${{ vars.MCP_SERVER_URL }}"}')

          SCAN_ID=$(echo $RESULT | jq -r '.scan_id')
          echo "scan_id=$SCAN_ID" >> $GITHUB_OUTPUT

          # Poll for results (max 5 minutes)
          for i in {1..30}; do
            RESPONSE=$(curl -s https://api.trusttrace.io/v1/scan/$SCAN_ID \
              -H "Authorization: Bearer ${{ secrets.TRUSTTRACE_API_KEY }}")
            STATUS=$(echo $RESPONSE | jq -r '.status')

            if [ "$STATUS" = "complete" ]; then
              echo "$RESPONSE" > scan_results.json
              break
            elif [ "$STATUS" = "failed" ]; then
              echo "::error::Scan failed: $(echo $RESPONSE | jq -r '.error')"
              exit 1
            fi
            sleep 10
          done

      - name: Check for Critical Findings
        run: |
          CRITICALS=$(cat scan_results.json | jq '[.findings[] | select(.severity == "critical")] | length')
          HIGHS=$(cat scan_results.json | jq '[.findings[] | select(.severity == "high")] | length')
          SCORE=$(cat scan_results.json | jq '.overall_score')

          echo "## TrustTrace Scan Results" >> $GITHUB_STEP_SUMMARY
          echo "Score: $SCORE/100" >> $GITHUB_STEP_SUMMARY
          echo "Critical: $CRITICALS | High: $HIGHS" >> $GITHUB_STEP_SUMMARY

          if [ "$CRITICALS" -gt 0 ]; then
            echo "::error::TrustTrace found $CRITICALS critical vulnerabilities"
            exit 1
          fi

Configuration

Add these to your repository settings:

Secrets (Settings → Secrets and variables → Actions):

  • TRUSTTRACE_API_KEY — your TrustTrace API key

Variables (Settings → Secrets and variables → Actions → Variables):

  • MCP_SERVER_URL — your MCP server endpoint URL

Scanning Uploaded Files

To scan dependency files or tool schemas instead of a live MCP server:

      - name: Scan Dependencies
        run: |
          RESULT=$(curl -s -X POST https://api.trusttrace.io/v1/scan/upload \
            -H "Authorization: Bearer ${{ secrets.TRUSTTRACE_API_KEY }}" \
            -F "files=@requirements.txt" \
            -F "files=@tool_schemas/agent_tools.json")

          SCAN_ID=$(echo $RESULT | jq -r '.scan_id')
          # ... poll for results same as above

GitLab CI

trusttrace-scan:
  stage: test
  image: curlimages/curl:latest
  script:
    - |
      RESULT=$(curl -s -X POST https://api.trusttrace.io/v1/scan/mcp \
        -H "Authorization: Bearer $TRUSTTRACE_API_KEY" \
        -H "Content-Type: application/json" \
        -d "{\"url\": \"$MCP_SERVER_URL\"}")

      SCAN_ID=$(echo $RESULT | jq -r '.scan_id')

      for i in $(seq 1 30); do
        RESPONSE=$(curl -s https://api.trusttrace.io/v1/scan/$SCAN_ID \
          -H "Authorization: Bearer $TRUSTTRACE_API_KEY")
        STATUS=$(echo $RESPONSE | jq -r '.status')
        if [ "$STATUS" = "complete" ]; then break; fi
        sleep 10
      done

      CRITICALS=$(echo $RESPONSE | jq '[.findings[] | select(.severity == "critical")] | length')
      if [ "$CRITICALS" -gt 0 ]; then
        echo "Critical vulnerabilities found: $CRITICALS"
        exit 1
      fi
  variables:
    MCP_SERVER_URL: "https://your-mcp-server.example.com/sse"

Add TRUSTTRACE_API_KEY to your GitLab CI/CD variables (Settings → CI/CD → Variables, masked).


Webhooks (Team+)

Instead of polling for results, configure a webhook to receive scan results automatically. This is useful for async pipelines or notification workflows.

Setup

curl -X PUT https://api.trusttrace.io/v1/account/webhook \
  -H "Authorization: Bearer sk_scan_your_key" \
  -H "Content-Type: application/json" \
  -d '{"webhook_url": "https://your-app.example.com/webhooks/trusttrace"}'

Webhook Payload

When a scan completes, TrustTrace sends:

{
  "scan_id": "a1b2c3d4...",
  "status": "complete",
  "overall_score": 43,
  "letter_grade": "D",
  "findings_count": {
    "critical": 3,
    "high": 5,
    "medium": 2,
    "low": 1
  }
}

Verifying Webhook Authenticity

Every webhook request includes an X-TrustTrace-Signature header. Verify it to ensure the request came from TrustTrace:

import hmac, hashlib

def verify(payload_body: bytes, signature: str, api_key: str) -> bool:
    expected = hmac.new(api_key.encode(), payload_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(signature, expected)

Best Practices

Scan on every PR — Catch issues before they're merged. Use the GitHub Action to block PRs with Critical findings.

Scan after dependency updates — Run an upload scan with your updated lockfile to check for newly introduced CVEs.

Set up baseline tracking — On Pro+ plans, regular MCP scans build a baseline. You'll catch tool definition changes (rug pulls) that appear between scans.

Don't store your API key in code — Use your CI/CD platform's secrets management (GitHub Secrets, GitLab Variables, etc.).

Fail builds on Critical only — Blocking on High findings during early adoption creates too much friction. Start with Critical-only gating, then tighten over time as your team resolves existing issues.