GitHub Actions Integration
This guide shows you how to integrate MCP Security Score into your GitHub Actions workflows using the API.
Prerequisites
- Pro subscription with API access
- API key from Dashboard → Settings
Setup
Step 1: Add Your API Key as a Secret
- Go to your GitHub repository
- Navigate to Settings → Secrets and variables → Actions
- Click New repository secret
- Name:
MCP_SCANNER_API_KEY - Value: Your API key (mcp_sk_...)
- Click Add secret
Step 2: Create the Workflow
Create .github/workflows/security-scan.yml:
name: MCP Security Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- name: Scan MCP Server
env:
MCP_SCANNER_API_KEY: ${{ secrets.MCP_SCANNER_API_KEY }}
run: |
set -e
REPO_URL="${{ github.server_url }}/${{ github.repository }}"
THRESHOLD=70
echo "Scanning $REPO_URL..."
# Create scan
SCAN_RESPONSE=$(curl -sf -X POST "https://mcpscanner.com/api/v1/scan" \
-H "Authorization: Bearer $MCP_SCANNER_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"url\": \"$REPO_URL\"}")
SCAN_ID=$(echo "$SCAN_RESPONSE" | jq -r '.id')
echo "Scan ID: $SCAN_ID"
# Poll for completion
for i in {1..24}; do
RESULT=$(curl -sf "https://mcpscanner.com/api/v1/scan/$SCAN_ID" \
-H "Authorization: Bearer $MCP_SCANNER_API_KEY")
STATUS=$(echo "$RESULT" | jq -r '.status')
echo "Status: $STATUS"
if [ "$STATUS" = "complete" ]; then
break
elif [ "$STATUS" = "failed" ]; then
echo "Scan failed!"
exit 1
fi
sleep 5
done
# Check results
SCORE=$(echo "$RESULT" | jq -r '.score')
GRADE=$(echo "$RESULT" | jq -r '.grade')
FINDINGS=$(echo "$RESULT" | jq -r '.findings | length')
echo ""
echo "=== Results ==="
echo "Score: $SCORE ($GRADE)"
echo "Findings: $FINDINGS"
if [ "$SCORE" -lt "$THRESHOLD" ]; then
echo "❌ Score $SCORE is below threshold $THRESHOLD"
exit 1
else
echo "✅ Security check passed"
fiComplete Example with Summary
This version adds a GitHub Actions summary with detailed results:
name: MCP Security Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
SCORE_THRESHOLD: 70
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- name: Scan MCP Server
id: scan
env:
MCP_SCANNER_API_KEY: ${{ secrets.MCP_SCANNER_API_KEY }}
run: |
set -e
REPO_URL="${{ github.server_url }}/${{ github.repository }}"
# Create scan
SCAN_RESPONSE=$(curl -sf -X POST "https://mcpscanner.com/api/v1/scan" \
-H "Authorization: Bearer $MCP_SCANNER_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"url\": \"$REPO_URL\"}")
SCAN_ID=$(echo "$SCAN_RESPONSE" | jq -r '.id')
echo "scan_id=$SCAN_ID" >> $GITHUB_OUTPUT
# Poll for completion (max 2 minutes)
for i in {1..24}; do
RESULT=$(curl -sf "https://mcpscanner.com/api/v1/scan/$SCAN_ID" \
-H "Authorization: Bearer $MCP_SCANNER_API_KEY")
STATUS=$(echo "$RESULT" | jq -r '.status')
if [ "$STATUS" = "complete" ] || [ "$STATUS" = "failed" ]; then
break
fi
sleep 5
done
# Extract results
SCORE=$(echo "$RESULT" | jq -r '.score')
GRADE=$(echo "$RESULT" | jq -r '.grade')
FINDINGS=$(echo "$RESULT" | jq -r '.findings | length')
CRITICAL=$(echo "$RESULT" | jq '[.findings[] | select(.severity == "critical")] | length')
HIGH=$(echo "$RESULT" | jq '[.findings[] | select(.severity == "high")] | length')
echo "score=$SCORE" >> $GITHUB_OUTPUT
echo "grade=$GRADE" >> $GITHUB_OUTPUT
echo "findings=$FINDINGS" >> $GITHUB_OUTPUT
echo "critical=$CRITICAL" >> $GITHUB_OUTPUT
echo "high=$HIGH" >> $GITHUB_OUTPUT
- name: Create Summary
run: |
echo "## MCP Security Scan Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Metric | Value |" >> $GITHUB_STEP_SUMMARY
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Score | ${{ steps.scan.outputs.score }} |" >> $GITHUB_STEP_SUMMARY
echo "| Grade | ${{ steps.scan.outputs.grade }} |" >> $GITHUB_STEP_SUMMARY
echo "| Total Findings | ${{ steps.scan.outputs.findings }} |" >> $GITHUB_STEP_SUMMARY
echo "| Critical | ${{ steps.scan.outputs.critical }} |" >> $GITHUB_STEP_SUMMARY
echo "| High | ${{ steps.scan.outputs.high }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "[View Full Report](https://mcpscanner.com/dashboard/scan/${{ steps.scan.outputs.scan_id }})" >> $GITHUB_STEP_SUMMARY
- name: Check Threshold
run: |
if [ ${{ steps.scan.outputs.score }} -lt ${{ env.SCORE_THRESHOLD }} ]; then
echo "❌ Security score ${{ steps.scan.outputs.score }} is below threshold ${{ env.SCORE_THRESHOLD }}"
exit 1
fi
echo "✅ Security check passed"Pull Request Only
Scan only on pull requests to save API calls:
name: PR Security Check
on:
pull_request:
branches: [main, develop]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
# ... same as aboveScheduled Scans
Run security scans on a schedule:
name: Weekly Security Scan
on:
schedule:
- cron: '0 9 * * 1' # Every Monday at 9 AM UTC
workflow_dispatch: # Allow manual trigger
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
# ... same as aboveReusable Workflow
Create a reusable workflow for multiple repositories:
# .github/workflows/mcp-scan.yml
name: MCP Scan
on:
workflow_call:
inputs:
threshold:
required: false
type: number
default: 70
secrets:
api_key:
required: true
jobs:
scan:
runs-on: ubuntu-latest
steps:
- name: Scan
env:
MCP_SCANNER_API_KEY: ${{ secrets.api_key }}
run: |
# ... scan logic hereCall from other workflows:
jobs:
security:
uses: ./.github/workflows/mcp-scan.yml
with:
threshold: 80
secrets:
api_key: ${{ secrets.MCP_SCANNER_API_KEY }}Troubleshooting
"Unauthorized" Error
Check that:
- Secret name is exactly
MCP_SCANNER_API_KEY - Secret is set at repository level
- API key is valid and not expired
Scan Times Out
Increase the poll iterations or timeout:
# Poll for longer (60 iterations × 5 seconds = 5 minutes)
for i in {1..60}; doRate Limit Exceeded
- Reduce scan frequency
- Use caching (scans are cached 24h)
- Upgrade to higher tier
Next Steps
- GitLab CI - GitLab integration
- Other CI Systems - Jenkins, CircleCI
- Rate Limits - Handling limits