Formatos de Salida¶
MCP-Scan soporta multiples formatos de salida para diferentes casos de uso.
Tabla de Contenidos¶
- Vision General
- Formato Texto
- Formato JSON
- Formato SARIF
- Evidence Bundle
- Comparativa de Formatos
- Procesamiento de Salidas
Vision General¶
| Formato | Extension | Uso Principal |
|---|---|---|
text |
- | Terminal, humanos |
json |
.json |
Procesamiento programatico |
sarif |
.sarif |
GitHub Code Scanning |
evidence |
.json |
Auditorias y compliance |
# Especificar formato
mcp-scan scan . --output text # Por defecto
mcp-scan scan . --output json
mcp-scan scan . --output sarif
mcp-scan scan . --output evidence
Formato Texto¶
Descripcion¶
Salida legible para humanos, ideal para uso en terminal.
Ejemplo de Salida¶
MCP-Scan v2.0.0
================================================================================
Scanning: /Users/ejemplo/mi-servidor-mcp
Mode: fast
Files: 5
Analyzing...
================================================================================
FINDINGS SUMMARY
================================================================================
CRITICAL: 1
- MCP-A003: Direct shell command execution
File: src/server.py
Line: 25
Code: subprocess.run(cmd, shell=True)
HIGH: 2
- MCP-B002: Potential path traversal
File: src/handlers.py
Line: 42
Code: open(filepath, 'r')
- MCP-C002: Unvalidated URL in request
File: src/api.py
Line: 18
Code: requests.get(url)
MEDIUM: 1
- MCP-E001: Hardcoded secret detected
File: src/config.py
Line: 5
Code: API_KEY = "sk-..."
================================================================================
SECURITY SCORE
================================================================================
MSSS Score: 45/100
Compliance Level: 0 (Not Compliant)
Category Breakdown:
A (RCE): 0/22 (-22 points)
B (Filesystem): 8/13 (-5 points)
C (SSRF): 5/10 (-5 points)
E (Secrets): 8/10 (-2 points)
Other: 24/45 (no deductions)
================================================================================
MCP SURFACE
================================================================================
Tools: 4
- execute_command (src/server.py:20)
- read_file (src/handlers.py:35)
- fetch_url (src/api.py:12)
- get_config (src/config.py:10)
SDK: Python Official (mcp)
Transport: stdio
================================================================================
Total: 4 findings (1 critical, 2 high, 1 medium)
Duration: 1.234s
Exit code: 1
Colores en Terminal¶
Por defecto, la salida usa colores:
| Severidad | Color |
|---|---|
| CRITICAL | Rojo brillante |
| HIGH | Rojo |
| MEDIUM | Amarillo |
| LOW | Azul |
| INFO | Gris |
Desactivar colores:
Formato JSON¶
Descripcion¶
Salida estructurada para procesamiento programatico.
Estructura del JSON¶
{
"version": "2.0.0",
"scan_info": {
"path": "/Users/ejemplo/mi-servidor-mcp",
"mode": "fast",
"started_at": "2026-01-23T10:00:00Z",
"finished_at": "2026-01-23T10:00:01Z",
"duration_ms": 1234
},
"manifest": {
"files": [
{
"path": "src/server.py",
"hash": "sha256:abc123...",
"size": 1024,
"language": "python"
}
],
"config_hash": "sha256:def456..."
},
"findings": [
{
"id": "f8a3b2c1d4e5f6a7",
"rule_id": "MCP-A003",
"title": "Direct shell command execution",
"description": "Tainted data flows to shell command execution",
"severity": "critical",
"confidence": "high",
"class": "A",
"location": {
"file": "src/server.py",
"line": 25,
"column": 5,
"end_line": 25,
"end_column": 45
},
"snippet": "subprocess.run(cmd, shell=True)",
"context": {
"before": ["@tool", "def execute_command(cmd: str):"],
"line": " return subprocess.run(cmd, shell=True)",
"after": [""]
},
"mcp_context": {
"tool_name": "execute_command",
"handler_name": "execute_command",
"transport": "stdio"
},
"evidence": {
"taint_trace": [
{
"step": 1,
"type": "source",
"location": "src/server.py:24:22",
"description": "Parameter 'cmd' from tool input"
},
{
"step": 2,
"type": "sink",
"location": "src/server.py:25:11",
"description": "subprocess.run with shell=True"
}
],
"llm_analysis": null,
"codeql_confirmed": false
},
"remediation": "Use subprocess.run with a list of arguments instead of shell=True"
}
],
"summary": {
"total": 4,
"by_severity": {
"critical": 1,
"high": 2,
"medium": 1,
"low": 0,
"info": 0
},
"by_class": {
"A": 1,
"B": 1,
"C": 1,
"E": 1
},
"baselined": 0
},
"mcp_surface": {
"tools": [
{
"name": "execute_command",
"handler": "execute_command",
"file": "src/server.py",
"line": 24,
"description": "Execute a system command",
"parameters": [
{
"name": "cmd",
"type": "str",
"required": true
}
]
}
],
"resources": [],
"prompts": [],
"sdk": "mcp",
"transport": "stdio",
"auth_signals": {
"cookies": false,
"headers": false,
"oauth_state": false,
"oauth_nonce": false
}
},
"msss_score": {
"score": 45,
"level": 0,
"level_name": "Not Compliant",
"category_scores": {
"A": {"max": 22, "score": 0, "penalty": 22},
"B": {"max": 13, "score": 8, "penalty": 5},
"C": {"max": 10, "score": 5, "penalty": 5},
"E": {"max": 10, "score": 8, "penalty": 2}
}
},
"exit_code": 1
}
Campos Principales¶
| Campo | Tipo | Descripcion |
|---|---|---|
version |
string | Version de mcp-scan |
scan_info |
object | Metadatos del escaneo |
manifest |
object | Inventario de archivos |
findings |
array | Lista de hallazgos |
summary |
object | Resumen estadistico |
mcp_surface |
object | Superficie MCP detectada |
msss_score |
object | Puntuacion de seguridad |
exit_code |
int | Codigo de salida |
Campos de Finding¶
| Campo | Tipo | Descripcion |
|---|---|---|
id |
string | ID unico (SHA-256 truncado) |
rule_id |
string | ID de la regla |
title |
string | Titulo del hallazgo |
description |
string | Descripcion detallada |
severity |
string | critical/high/medium/low/info |
confidence |
string | high/medium/low |
class |
string | Clase de vulnerabilidad (A-N) |
location |
object | Ubicacion en codigo |
snippet |
string | Codigo relevante |
context |
object | Lineas alrededor |
mcp_context |
object | Contexto MCP |
evidence |
object | Evidencias adicionales |
remediation |
string | Como arreglar |
Formato SARIF¶
Descripcion¶
Static Analysis Results Interchange Format (SARIF) 2.1.0, compatible con:
- GitHub Code Scanning
- Azure DevOps
- Visual Studio
- Otras herramientas SARIF-compatibles
Estructura SARIF¶
{
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
"version": "2.1.0",
"runs": [
{
"tool": {
"driver": {
"name": "mcp-scan",
"version": "2.0.0",
"informationUri": "https://github.com/mcphub/mcp-scan",
"rules": [
{
"id": "MCP-A003",
"name": "DirectShellExecution",
"shortDescription": {
"text": "Direct shell command execution"
},
"fullDescription": {
"text": "Tainted data flows directly to a shell command execution function without proper sanitization."
},
"helpUri": "https://mcphub.io/docs/rules/MCP-A003",
"defaultConfiguration": {
"level": "error"
},
"properties": {
"tags": ["security", "rce", "command-injection"],
"security-severity": "9.8"
}
}
]
}
},
"results": [
{
"ruleId": "MCP-A003",
"ruleIndex": 0,
"level": "error",
"message": {
"text": "Tainted data from tool input 'cmd' flows to subprocess.run with shell=True"
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "src/server.py",
"uriBaseId": "%SRCROOT%"
},
"region": {
"startLine": 25,
"startColumn": 5,
"endLine": 25,
"endColumn": 45,
"snippet": {
"text": "subprocess.run(cmd, shell=True)"
}
}
}
}
],
"codeFlows": [
{
"threadFlows": [
{
"locations": [
{
"location": {
"physicalLocation": {
"artifactLocation": {
"uri": "src/server.py"
},
"region": {
"startLine": 24,
"startColumn": 22
}
},
"message": {
"text": "Source: Parameter 'cmd' from tool input"
}
}
},
{
"location": {
"physicalLocation": {
"artifactLocation": {
"uri": "src/server.py"
},
"region": {
"startLine": 25,
"startColumn": 11
}
},
"message": {
"text": "Sink: subprocess.run with shell=True"
}
}
}
]
}
]
}
],
"fingerprints": {
"primaryLocationLineHash": "f8a3b2c1d4e5f6a7"
}
}
]
}
]
}
Mapeo de Severidades¶
| MCP-Scan | SARIF Level | Security Severity |
|---|---|---|
| critical | error | 9.0-10.0 |
| high | error | 7.0-8.9 |
| medium | warning | 4.0-6.9 |
| low | note | 1.0-3.9 |
| info | none | 0.0 |
Uso con GitHub Code Scanning¶
# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
jobs:
mcp-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run MCP-Scan
run: |
mcp-scan scan . --output sarif > results.sarif
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
Evidence Bundle¶
Descripcion¶
Paquete completo de evidencias para auditorias y compliance.
Estructura del Evidence Bundle¶
{
"bundle_version": "1.0",
"generated_at": "2026-01-23T10:00:00Z",
"scan_info": {
"tool": "mcp-scan",
"version": "2.0.0",
"path": "/Users/ejemplo/mi-servidor-mcp",
"mode": "deep",
"config_hash": "sha256:abc123..."
},
"manifest": {
"total_files": 5,
"total_size_bytes": 12345,
"files": [
{
"path": "src/server.py",
"sha256": "abc123def456...",
"size": 1024,
"language": "python",
"last_modified": "2026-01-20T15:30:00Z"
}
]
},
"mcp_surface": {
"sdk": {
"name": "mcp",
"version": "1.0.0",
"detected_from": "import statement"
},
"transport": {
"type": "stdio",
"detected_from": "server.run()"
},
"tools": [
{
"name": "execute_command",
"handler": "execute_command",
"file": "src/server.py",
"line": 24,
"description": "Execute a system command",
"description_hash": "sha256:...",
"parameters": [
{
"name": "cmd",
"type": "str",
"description": "Command to execute",
"required": true
}
],
"return_type": "str",
"is_async": false,
"decorators": ["@tool"]
}
],
"resources": [],
"prompts": [],
"auth_signals": {
"cookies": false,
"headers": false,
"oauth_state": false,
"oauth_nonce": false
}
},
"findings": [
{
"id": "f8a3b2c1d4e5f6a7",
"rule_id": "MCP-A003",
"title": "Direct shell command execution",
"description": "...",
"severity": "critical",
"confidence": "high",
"class": "A",
"location": {
"file": "src/server.py",
"line": 25,
"column": 5,
"file_hash": "sha256:abc123..."
},
"snippet": {
"text": "subprocess.run(cmd, shell=True)",
"hash": "sha256:..."
},
"context": {
"before": ["@tool", "def execute_command(cmd: str):"],
"line": " return subprocess.run(cmd, shell=True)",
"after": [""]
},
"mcp_context": {
"tool_name": "execute_command",
"handler_name": "execute_command",
"transport": "stdio",
"in_tool_handler": true
},
"evidence": {
"taint_trace": [
{
"step": 1,
"type": "source",
"source_type": "tool_input",
"location": {
"file": "src/server.py",
"line": 24,
"column": 22
},
"code": "cmd: str",
"description": "Parameter 'cmd' from tool input"
},
{
"step": 2,
"type": "sink",
"sink_type": "exec",
"location": {
"file": "src/server.py",
"line": 25,
"column": 11
},
"code": "subprocess.run(cmd, shell=True)",
"description": "subprocess.run with shell=True"
}
],
"sanitizers_found": [],
"llm_analysis": {
"analyzed": true,
"is_injection": false,
"confidence": 0.0,
"category": "benign",
"reason": "Not a prompt injection, this is command injection"
},
"ml_analysis": {
"analyzed": true,
"is_injection": false,
"confidence": 0.1,
"category": "benign"
},
"codeql_confirmed": true
},
"remediation": {
"text": "Use subprocess.run with a list of arguments",
"example": "subprocess.run(['command', 'arg1', 'arg2'])"
}
}
],
"summary": {
"total_findings": 4,
"by_severity": {
"critical": 1,
"high": 2,
"medium": 1,
"low": 0,
"info": 0
},
"by_class": {
"A": 1,
"B": 1,
"C": 1,
"E": 1
},
"baselined": 0
},
"msss_score": {
"score": 45,
"max_score": 100,
"level": 0,
"level_name": "Not Compliant",
"level_requirements": {
"level_1": 60,
"level_2": 80,
"level_3": 90
},
"category_breakdown": {
"A": {
"weight": 0.22,
"max_points": 22,
"earned_points": 0,
"penalty": 22,
"findings": 1
},
"B": {
"weight": 0.13,
"max_points": 13,
"earned_points": 8,
"penalty": 5,
"findings": 1
}
},
"penalties": {
"critical_findings": 1,
"critical_multiplier": 2.0,
"total_penalty": 34
}
},
"duration": {
"total_ms": 5234,
"discovery_ms": 120,
"parsing_ms": 890,
"surface_ms": 234,
"analysis_ms": 3456,
"reporting_ms": 534
},
"checksums": {
"manifest": "sha256:...",
"findings": "sha256:...",
"bundle": "sha256:..."
}
}
Uso para Auditorias¶
El Evidence Bundle es util para:
- Auditorias de seguridad - Evidencia completa de analisis
- Compliance - Documentacion de due diligence
- Certificacion - Prueba de analisis de seguridad
- Forensics - Investigacion de incidentes
# Generar evidence bundle con modo deep
mcp-scan scan . --mode deep --output evidence > audit-2026-01-23.json
# Verificar integridad
sha256sum audit-2026-01-23.json
Comparativa de Formatos¶
| Caracteristica | Text | JSON | SARIF | Evidence |
|---|---|---|---|---|
| Legible humanos | Si | Parcial | No | Parcial |
| Procesable | No | Si | Si | Si |
| GitHub compatible | No | No | Si | No |
| Taint traces | Parcial | Si | Si | Completo |
| Hashes archivos | No | Si | No | Si |
| Timing detallado | No | Basico | No | Completo |
| Checksums | No | No | No | Si |
| Tamano | Pequeno | Medio | Medio | Grande |
Recomendaciones por Caso de Uso¶
| Caso de Uso | Formato Recomendado |
|---|---|
| Desarrollo local | text |
| CI/CD general | json |
| GitHub Actions | sarif |
| GitLab CI | json o sarif |
| Auditoria formal | evidence |
| Compliance | evidence |
| Debugging | json |
| Reportes ejecutivos | text |
Procesamiento de Salidas¶
Procesar JSON con jq¶
# Total de hallazgos
mcp-scan scan . -o json | jq '.summary.total'
# Solo criticos
mcp-scan scan . -o json | jq '.findings[] | select(.severity == "critical")'
# Listar archivos afectados
mcp-scan scan . -o json | jq '[.findings[].location.file] | unique'
# Score MSSS
mcp-scan scan . -o json | jq '.msss_score.score'
# Hallazgos por clase
mcp-scan scan . -o json | jq '.summary.by_class'
Procesar con Python¶
import json
import subprocess
# Ejecutar scan
result = subprocess.run(
["mcp-scan", "scan", ".", "--output", "json"],
capture_output=True,
text=True
)
# Parsear resultados
data = json.loads(result.stdout)
# Analizar
print(f"Total: {data['summary']['total']}")
print(f"Score: {data['msss_score']['score']}")
for finding in data['findings']:
if finding['severity'] == 'critical':
print(f"CRITICAL: {finding['title']} @ {finding['location']['file']}:{finding['location']['line']}")
Convertir Formatos¶
# JSON a texto resumido
mcp-scan scan . -o json | jq -r '.findings[] | "\(.severity | ascii_upcase): \(.rule_id) - \(.title) @ \(.location.file):\(.location.line)"'
# Extraer solo hallazgos de JSON
mcp-scan scan . -o json | jq '.findings' > findings-only.json
# Extraer surface de JSON
mcp-scan scan . -o json | jq '.mcp_surface' > surface.json
Anterior: Modos de Analisis | Siguiente: Gestion de Baselines