Skip to content

CI/CD Integration

Integrate MCP-Scan into your CI/CD pipeline to catch security issues before deployment.

GitHub Actions

Basic Workflow

# .github/workflows/security.yml
name: Security Scan

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

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

      - name: Setup Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.24'

      - name: Install MCP-Scan
        run: go install github.com/mcphub/mcp-scan/cmd/mcp-scan@latest

      - name: Run Security Scan
        run: mcp-scan scan . --fail-on high

With GitHub Code Scanning

name: Security Scan with Code Scanning

on:
  push:
    branches: [main]
  pull_request:

jobs:
  mcp-scan:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
      contents: read

    steps:
      - uses: actions/checkout@v4

      - name: Setup Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.24'

      - name: Install MCP-Scan
        run: go install github.com/mcphub/mcp-scan/cmd/mcp-scan@latest

      - name: Run Scan
        run: mcp-scan scan . --output sarif > results.sarif
        continue-on-error: true

      - name: Upload SARIF
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: results.sarif
          category: mcp-scan

With Baseline (Progressive Hardening)

name: Security Scan with Baseline

on: [push, pull_request]

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

      - name: Setup Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.24'

      - name: Install MCP-Scan
        run: go install github.com/mcphub/mcp-scan/cmd/mcp-scan@latest

      - name: Run Scan with Baseline
        run: |
          mcp-scan scan . \
            --baseline .mcp-scan-baseline.json \
            --fail-on high \
            --output json > results.json

      - name: Upload Results
        uses: actions/upload-artifact@v4
        with:
          name: security-results
          path: results.json

GitLab CI

# .gitlab-ci.yml
stages:
  - security

mcp-scan:
  stage: security
  image: golang:1.24
  script:
    - go install github.com/mcphub/mcp-scan/cmd/mcp-scan@latest
    - mcp-scan scan . --output sarif > gl-sast-report.json
  artifacts:
    reports:
      sast: gl-sast-report.json
    paths:
      - gl-sast-report.json
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Azure DevOps

# azure-pipelines.yml
trigger:
  - main

pool:
  vmImage: 'ubuntu-latest'

steps:
  - task: GoTool@0
    inputs:
      version: '1.24'

  - script: |
      go install github.com/mcphub/mcp-scan/cmd/mcp-scan@latest
      mcp-scan scan . --output sarif > $(Build.ArtifactStagingDirectory)/results.sarif
    displayName: 'Run MCP-Scan'

  - task: PublishBuildArtifacts@1
    inputs:
      PathtoPublish: '$(Build.ArtifactStagingDirectory)'
      ArtifactName: 'security-results'

CircleCI

# .circleci/config.yml
version: 2.1

jobs:
  security-scan:
    docker:
      - image: cimg/go:1.24
    steps:
      - checkout
      - run:
          name: Install MCP-Scan
          command: go install github.com/mcphub/mcp-scan/cmd/mcp-scan@latest
      - run:
          name: Run Security Scan
          command: mcp-scan scan . --fail-on high
      - store_artifacts:
          path: results.json

workflows:
  security:
    jobs:
      - security-scan

Jenkins

// Jenkinsfile
pipeline {
    agent any

    tools {
        go 'go-1.24'
    }

    stages {
        stage('Security Scan') {
            steps {
                sh 'go install github.com/mcphub/mcp-scan/cmd/mcp-scan@latest'
                sh 'mcp-scan scan . --output json > results.json'
                sh 'mcp-scan scan . --fail-on high'
            }
            post {
                always {
                    archiveArtifacts artifacts: 'results.json'
                }
            }
        }
    }
}

Docker

Using Docker Image

docker run --rm -v $(pwd):/scan mcphub/mcp-scan scan /scan --fail-on high

In Docker Compose

# docker-compose.yml
services:
  security-scan:
    image: mcphub/mcp-scan:latest
    volumes:
      - .:/scan:ro
    command: scan /scan --output json

Best Practices

1. Use Appropriate Modes

# PR checks: fast mode for quick feedback
- name: Quick Scan
  if: github.event_name == 'pull_request'
  run: mcp-scan scan . --mode fast --fail-on high

# Main branch: deep mode for thorough analysis
- name: Deep Scan
  if: github.ref == 'refs/heads/main'
  run: mcp-scan scan . --mode deep --output sarif > results.sarif

2. Progressive Hardening with Baselines

# Initial: Generate baseline for existing findings
mcp-scan baseline generate . --reason "Initial baseline" --accepted-by "security@company.com"

# CI: Fail only on new findings
mcp-scan scan . --baseline .mcp-scan-baseline.json --fail-on high

3. Appropriate Fail Thresholds

Environment Recommended --fail-on
Development critical
Pull Request high
Main Branch high
Release medium
Security Audit low

4. Cache Dependencies

# GitHub Actions
- name: Cache Go modules
  uses: actions/cache@v4
  with:
    path: ~/go/pkg/mod
    key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}

5. Timeout Configuration

- name: Run Scan
  run: mcp-scan scan . --timeout 5m
  timeout-minutes: 10  # Pipeline timeout > scan timeout

Exit Codes Reference

Code Meaning CI Action
0 No findings above threshold Pass
1 Findings above threshold Fail
2 Configuration error Fail
3 Scan error Fail

Notifications

Slack Notification on Findings

- name: Notify Slack
  if: failure()
  uses: slackapi/slack-github-action@v1
  with:
    payload: |
      {
        "text": "Security scan found issues in ${{ github.repository }}"
      }
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

Email on Critical Findings

- name: Send Email
  if: failure()
  uses: dawidd6/action-send-mail@v3
  with:
    server_address: smtp.example.com
    to: security@company.com
    subject: Critical security findings in ${{ github.repository }}
    body: Check the scan results at ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}