Construye un flujo de trabajo de control de calidad del código
En esta sección, construirás un flujo de trabajo completo de automatización de calidad de código paso a paso. Comenzarás creando un sandbox de E2B con servidores MCP de GitHub y SonarQube, luego agregarás funcionalidad de forma progresiva hasta tener un flujo de trabajo listo para producción que analice la calidad del código y cree pull requests.
Al trabajar en cada paso de manera secuencial, aprenderás cómo funcionan los servidores MCP, cómo interactuar con ellos a través de Claude y cómo encadenar operaciones para construir flujos de trabajo de automatización potentes.
Requisitos previos
Antes de comenzar, asegúrate de tener:
Una cuenta de E2B con acceso a la API
- Note
Este ejemplo utiliza Claude CLI, que viene preinstalado en los sandboxes de E2B, pero puedes adaptar el ejemplo para trabajar con otros asistentes de IA de tu elección. Consulta la documentación de MCP de E2B para conocer métodos de conexión alternativos.
Una cuenta de GitHub con:
- Un repositorio que contenga el código a analizar
- Un token de acceso personal con el alcance
repo
Una cuenta de SonarCloud con:
- Una organización creada
- Un proyecto configurado para tu repositorio
- Un token de usuario generado
Entornos de ejecución de lenguajes instalados:
- TypeScript: Node.js 18+
- Python: Python 3.8+
NoteEsta guía utiliza la opción
--dangerously-skip-permissionsde Claude para habilitar la ejecución automatizada de comandos en los sandboxes de E2B. Esta opción omite las solicitudes de permisos, lo cual es adecuado para entornos de contenedores aislados como E2B, donde los sandboxes son desechables y están separados de tu máquina local.Sin embargo, ten en cuenta que Claude puede ejecutar cualquier comando dentro del sandbox, incluyendo el acceso a archivos y credenciales disponibles en ese entorno. Utiliza este enfoque únicamente con código y flujos de trabajo de confianza. Para obtener más información, consulta las instrucciones de Anthropic sobre seguridad en contenedores.
Configura tu proyecto
Crea un nuevo directorio para tu flujo de trabajo e inicializa Node.js:
mkdir github-sonarqube-workflow cd github-sonarqube-workflow npm init -yAbre
package.jsony configúralo para módulos ES:{ "name": "github-sonarqube-workflow", "version": "1.0.0", "description": "Flujo de trabajo automatizado de calidad de código usando E2B, GitHub y SonarQube", "type": "module", "main": "quality-workflow.ts", "scripts": { "start": "tsx quality-workflow.ts" }, "keywords": ["e2b", "github", "sonarqube", "mcp", "code-quality"], "author": "", "license": "MIT" }Instala las dependencias requeridas:
npm install e2b dotenv npm install -D typescript tsx @types/nodeCrea un archivo
.enven la raíz de tu proyecto:touch .envAgrega tus claves de API y configuración, reemplazando los marcadores de posición con tus credenciales reales:
E2B_API_KEY=tu_clave_de_api_de_e2b_aqui ANTHROPIC_API_KEY=tu_clave_de_api_de_anthropic_aqui GITHUB_TOKEN=ghp_tu_token_de_acceso_personal_aqui GITHUB_OWNER=tu_usuario_de_github GITHUB_REPO=tu_nombre_de_repositorio SONARQUBE_ORG=tu_clave_de_organizacion_de_sonarcloud SONARQUBE_TOKEN=tu_token_de_usuario_de_sonarqube SONARQUBE_URL=https://sonarcloud.ioProtege tus credenciales agregando
.enva.gitignore:echo ".env" >> .gitignore echo "node_modules/" >> .gitignore
Crea un nuevo directorio para tu flujo de trabajo:
mkdir github-sonarqube-workflow cd github-sonarqube-workflowCrea un entorno virtual y actívalo:
python3 -m venv venv source venv/bin/activate # En Windows: venv\Scripts\activateInstala las dependencias requeridas:
pip install e2b python-dotenvCrea un archivo
.enven la raíz de tu proyecto:touch .envAgrega tus claves de API y configuración, reemplazando los marcadores de posición con tus credenciales reales:
E2B_API_KEY=tu_clave_de_api_de_e2b_aqui ANTHROPIC_API_KEY=tu_clave_de_api_de_anthropic_aqui GITHUB_TOKEN=ghp_tu_token_de_acceso_personal_aqui GITHUB_OWNER=tu_usuario_de_github GITHUB_REPO=tu_nombre_de_repositorio SONARQUBE_ORG=tu_clave_de_organizacion_de_sonarcloud SONARQUBE_TOKEN=tu_token_de_usuario_de_sonarqube SONARQUBE_URL=https://sonarcloud.ioProtege tus credenciales agregando
.enva.gitignore:echo ".env" >> .gitignore echo "venv/" >> .gitignore echo "__pycache__/" >> .gitignore
Paso 1: Crea tu primer sandbox
Comencemos creando un sandbox y verificando que los servidores MCP estén configurados correctamente.
Crea un archivo llamado 01-test-connection.ts en la raíz de tu proyecto:
import "dotenv/config";
import { Sandbox } from "e2b";
async function testConnection() {
console.log(
"Creando sandbox de E2B con servidores MCP de GitHub y SonarQube...\n",
);
const sbx = await Sandbox.betaCreate({
envs: {
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
GITHUB_TOKEN: process.env.GITHUB_TOKEN!,
SONARQUBE_TOKEN: process.env.SONARQUBE_TOKEN!,
},
mcp: {
githubOfficial: {
githubPersonalAccessToken: process.env.GITHUB_TOKEN!,
},
sonarqube: {
org: process.env.SONARQUBE_ORG!,
token: process.env.SONARQUBE_TOKEN!,
url: "https://sonarcloud.io",
},
},
});
const mcpUrl = sbx.betaGetMcpUrl();
const mcpToken = await sbx.betaGetMcpToken();
console.log("¡Sandbox creado con éxito!");
console.log(`URL de la pasarela MCP (MCP Gateway): ${mcpUrl}\n`);
// Esperar a la inicialización de MCP
await new Promise((resolve) => setTimeout(resolve, 1000));
// Configurar Claude para usar la pasarela MCP
console.log("Conectando Claude CLI a la pasarela MCP...");
await sbx.commands.run(
`claude mcp add --transport http e2b-mcp-gateway ${mcpUrl} --header "Authorization: Bearer ${mcpToken}"`,
{
timeoutMs: 0,
onStdout: console.log,
onStderr: console.log,
},
);
console.log("\n¡Conexión exitosa! Limpiando recursos...");
await sbx.kill();
}
testConnection().catch(console.error);Ejecuta este script para verificar tu configuración:
npx tsx 01-test-connection.tsCrea un archivo llamado 01_test_connection.py en la raíz de tu proyecto:
import os
import asyncio
from dotenv import load_dotenv
from e2b import AsyncSandbox
load_dotenv()
async def test_connection():
print("Creando sandbox de E2B con servidores MCP de GitHub y SonarQube...\n")
sbx = await AsyncSandbox.beta_create(
envs={
"ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY"),
"GITHUB_TOKEN": os.getenv("GITHUB_TOKEN"),
"SONARQUBE_TOKEN": os.getenv("SONARQUBE_TOKEN"),
},
mcp={
"githubOfficial": {
"githubPersonalAccessToken": os.getenv("GITHUB_TOKEN"),
},
"sonarqube": {
"org": os.getenv("SONARQUBE_ORG"),
"token": os.getenv("SONARQUBE_TOKEN"),
"url": "https://sonarcloud.io",
},
},
)
mcp_url = sbx.beta_get_mcp_url()
mcp_token = await sbx.beta_get_mcp_token()
print("¡Sandbox creado con éxito!")
print(f"URL de la pasarela MCP (MCP Gateway): {mcp_url}\n")
# Esperar a la inicialización de MCP
await asyncio.sleep(1)
# Configurar Claude para usar la pasarela MCP
print("Conectando Claude CLI a la pasarela MCP...")
await sbx.commands.run(
f'claude mcp add --transport http e2b-mcp-gateway {mcp_url} --header "Authorization: Bearer {mcp_token}"',
timeout=0,
on_stdout=print,
on_stderr=print,
)
print("\n¡Conexión exitosa! Limpiando recursos...")
await sbx.kill()
if __name__ == "__main__":
asyncio.run(test_connection())Ejecuta este script para verificar tu configuración:
python 01_test_connection.pyLa salida debería ser similar al siguiente ejemplo:
Creando sandbox de E2B con servidores MCP de GitHub y SonarQube...
✓ ¡Sandbox creado con éxito!
URL de la pasarela MCP (MCP Gateway): https://50005-xxxxx.e2b.app/mcp
Conectando Claude CLI a la pasarela MCP...
Added HTTP MCP server e2b-mcp-gateway with URL: https://50005-xxxxx.e2b.app/mcp to local config
Headers: {
"Authorization": "Bearer xxxxx-xxxx-xxxx"
}
File modified: /home/user/.claude.json [project: /home/user]
✓ ¡Conexión exitosa! Limpiando recursos...
Acabas de aprender cómo crear un sandbox de E2B con múltiples servidores MCP configurados. El método betaCreate inicializa un entorno en la nube con Claude CLI y los servidores MCP especificados.
Paso 2: Descubre las herramientas de MCP disponibles
Los servidores MCP exponen herramientas que Claude puede invocar. El servidor MCP de GitHub proporciona herramientas de gestión de repositorios, mientras que SonarQube proporciona herramientas de análisis de código. Al listar sus herramientas, sabrás qué operaciones son posibles.
Para probar la enumeración de herramientas MCP:
Crea 02-list-tools.ts:
import "dotenv/config";
import { Sandbox } from "e2b";
async function listTools() {
console.log("Creando sandbox...\n");
const sbx = await Sandbox.betaCreate({
envs: {
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
GITHUB_TOKEN: process.env.GITHUB_TOKEN!,
SONARQUBE_TOKEN: process.env.SONARQUBE_TOKEN!,
},
mcp: {
githubOfficial: {
githubPersonalAccessToken: process.env.GITHUB_TOKEN!,
},
sonarqube: {
org: process.env.SONARQUBE_ORG!,
token: process.env.SONARQUBE_TOKEN!,
url: "https://sonarcloud.io",
},
},
});
const mcpUrl = sbx.betaGetMcpUrl();
const mcpToken = await sbx.betaGetMcpToken();
// Esperar a la inicialización de MCP
await new Promise((resolve) => setTimeout(resolve, 1000));
await sbx.commands.run(
`claude mcp add --transport http e2b-mcp-gateway ${mcpUrl} --header "Authorization: Bearer ${mcpToken}"`,
{ timeoutMs: 0, onStdout: console.log, onStderr: console.log },
);
console.log("\nDescubriendo herramientas de MCP disponibles...\n");
const prompt =
"Lista todas las herramientas MCP a las que tienes acceso. Para cada herramienta, muestra su nombre exacto y una breve descripción.";
await sbx.commands.run(
`echo '${prompt}' | claude -p --dangerously-skip-permissions`,
{ timeoutMs: 0, onStdout: console.log, onStderr: console.log },
);
await sbx.kill();
}
listTools().catch(console.error);Ejecuta el script:
npx tsx 02-list-tools.tsCrea 02_list_tools.py:
import os
import asyncio
from dotenv import load_dotenv
from e2b import AsyncSandbox
load_dotenv()
async def list_tools():
print("Creando sandbox...\n")
sbx = await AsyncSandbox.beta_create(
envs={
"ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY"),
"GITHUB_TOKEN": os.getenv("GITHUB_TOKEN"),
"SONARQUBE_TOKEN": os.getenv("SONARQUBE_TOKEN"),
},
mcp={
"githubOfficial": {
"githubPersonalAccessToken": os.getenv("GITHUB_TOKEN"),
},
"sonarqube": {
"org": os.getenv("SONARQUBE_ORG"),
"token": os.getenv("SONARQUBE_TOKEN"),
"url": "https://sonarcloud.io",
},
},
)
mcp_url = sbx.beta_get_mcp_url()
mcp_token = await sbx.beta_get_mcp_token()
# Esperar a la inicialización de MCP
await asyncio.sleep(1)
await sbx.commands.run(
f'claude mcp add --transport http e2b-mcp-gateway {mcp_url} --header "Authorization: Bearer {mcp_token}"',
timeout=0,
on_stdout=print,
on_stderr=print,
)
print("\nDescubriendo herramientas de MCP disponibles...\n")
prompt = "Lista todas las herramientas MCP a las que tienes acceso. Para cada herramienta, muestra su nombre exacto y una breve descripción."
await sbx.commands.run(
f"echo '{prompt}' | claude -p --dangerously-skip-permissions",
timeout=0,
on_stdout=print,
on_stderr=print,
)
await sbx.kill()
if __name__ == "__main__":
asyncio.run(list_tools())Ejecuta el script:
python 02_list_tools.pyEn la consola, deberías ver una lista de herramientas MCP:
Creando sandbox...
Sandbox creado
Conectando a la pasarela MCP...
Descubriendo herramientas de MCP disponibles...
Tengo acceso a las siguientes herramientas de MCP:
**Herramientas de GitHub:**
1. mcp__create_repository - Crea un nuevo repositorio de GitHub
2. mcp__list_issues - Lista los issues en un repositorio
3. mcp__create_issue - Crea un nuevo issue
4. mcp__get_file_contents - Obtiene el contenido de un archivo de un repositorio
5. mcp__create_or_update_file - Crea o actualiza archivos en un repositorio
6. mcp__create_pull_request - Crea un pull request
7. mcp__create_branch - Crea una nueva rama
8. mcp__push_files - Envía múltiples archivos en un único commit
... (más de 30 herramientas de GitHub adicionales)
**Herramientas de SonarQube:**
1. mcp__get_projects - Lista los proyectos en la organización
2. mcp__get_quality_gate_status - Obtiene el estado del quality gate para un proyecto
3. mcp__list_project_issues - Lista los problemas de calidad en un proyecto
4. mcp__search_issues - Busca problemas de calidad específicos
... (herramientas de análisis de SonarQube)
Paso 3: Prueba las herramientas de MCP de GitHub
Probemos GitHub utilizando herramientas MCP. Empecemos de forma sencilla listando los issues del repositorio.
Crea 03-test-github.ts:
import "dotenv/config";
import { Sandbox } from "e2b";
async function testGitHub() {
console.log("Creando sandbox...\n");
const sbx = await Sandbox.betaCreate({
envs: {
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
GITHUB_TOKEN: process.env.GITHUB_TOKEN!,
},
mcp: {
githubOfficial: {
githubPersonalAccessToken: process.env.GITHUB_TOKEN!,
},
},
});
const mcpUrl = sbx.betaGetMcpUrl();
const mcpToken = await sbx.betaGetMcpToken();
await new Promise((resolve) => setTimeout(resolve, 1000));
await sbx.commands.run(
`claude mcp add --transport http e2b-mcp-gateway ${mcpUrl} --header "Authorization: Bearer ${mcpToken}"`,
{ timeoutMs: 0, onStdout: console.log, onStderr: console.log },
);
const repoPath = `${process.env.GITHUB_OWNER}/${process.env.GITHUB_REPO}`;
console.log(`\nListando issues en ${repoPath}...\n`);
const prompt = `Usando las herramientas de MCP de GitHub, lista todos los issues abiertos en el repositorio "${repoPath}". Muestra el número de issue, título y autor para cada uno.`;
await sbx.commands.run(
`echo '${prompt.replace(/'/g, "'\\''")}' | claude -p --dangerously-skip-permissions`,
{
timeoutMs: 0,
onStdout: console.log,
onStderr: console.log,
},
);
await sbx.kill();
}
testGitHub().catch(console.error);Ejecuta el script:
npx tsx 03-test-github.tsCrea 03_test_github.py:
import os
import asyncio
from dotenv import load_dotenv
from e2b import AsyncSandbox
load_dotenv()
async def test_github():
print("Creando sandbox...\n")
sbx = await AsyncSandbox.beta_create(
envs={
"ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY"),
"GITHUB_TOKEN": os.getenv("GITHUB_TOKEN"),
},
mcp={
"githubOfficial": {
"githubPersonalAccessToken": os.getenv("GITHUB_TOKEN"),
},
},
)
mcp_url = sbx.beta_get_mcp_url()
mcp_token = await sbx.beta_get_mcp_token()
await asyncio.sleep(1)
await sbx.commands.run(
f'claude mcp add --transport http e2b-mcp-gateway {mcp_url} --header "Authorization: Bearer {mcp_token}"',
timeout=0,
on_stdout=print,
on_stderr=print,
)
repo_path = f"{os.getenv('GITHUB_OWNER')}/{os.getenv('GITHUB_REPO')}"
print(f"\nListando issues en {repo_path}...\n")
prompt = f'Usando las herramientas de MCP de GitHub, lista todos los issues abiertos en el repositorio "{repo_path}". Muestra el número de issue, título y autor para cada uno.'
await sbx.commands.run(
f"echo '{prompt}' | claude -p --dangerously-skip-permissions",
timeout=0,
on_stdout=print,
on_stderr=print,
)
await sbx.kill()
if __name__ == "__main__":
asyncio.run(test_github())Ejecuta el script:
python 03_test_github.pyDeberías ver a Claude usar las herramientas de MCP de GitHub para listar los issues de tu repositorio:
Creando sandbox...
Conectando a la pasarela MCP...
Listando issues en <tu-repositorio>...
Aquí están los primeros 10 issues abiertos en el repositorio <tu-repositorio>:
1. **Issue #23577**: Actualizar README (autor: usuario1)
2. **Issue #23575**: notas de lanzamiento para la versión de Compose v2.40.1 (autor: usuario2)
3. **Issue #23570**: engine-cli: corregir salida de `docker volume prune` (autor: usuario3)
4. **Issue #23568**: Actualización de Engdocs (autor: usuario4)
5. **Issue #23565**: agregar nueva sección (autor: usuario5)
... (continúa con más issues)
Ahora puedes enviar prompts a Claude e interactuar con GitHub mediante lenguaje natural. Claude decide qué herramienta invocar según tu prompt.
Paso 4: Prueba las herramientas de MCP de SonarQube
Analicemos la calidad del código usando las herramientas de MCP de SonarQube.
Crea 04-test-sonarqube.ts:
import "dotenv/config";
import { Sandbox } from "e2b";
async function testSonarQube() {
console.log("Creando sandbox...\n");
const sbx = await Sandbox.betaCreate({
envs: {
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
GITHUB_TOKEN: process.env.GITHUB_TOKEN!,
SONARQUBE_TOKEN: process.env.SONARQUBE_TOKEN!,
},
mcp: {
githubOfficial: {
githubPersonalAccessToken: process.env.GITHUB_TOKEN!,
},
sonarqube: {
org: process.env.SONARQUBE_ORG!,
token: process.env.SONARQUBE_TOKEN!,
url: "https://sonarcloud.io",
},
},
});
const mcpUrl = sbx.betaGetMcpUrl();
const mcpToken = await sbx.betaGetMcpToken();
await new Promise((resolve) => setTimeout(resolve, 1000));
await sbx.commands.run(
`claude mcp add --transport http e2b-mcp-gateway ${mcpUrl} --header "Authorization: Bearer ${mcpToken}"`,
{ timeoutMs: 0, onStdout: console.log, onStderr: console.log },
);
console.log("\nAnalizando la calidad del código con SonarQube...\n");
const prompt = `Usando las herramientas de MCP de SonarQube:
1. Lista todos los proyectos en mi organización
2. Para el primer proyecto, muestra:
- Estado del quality gate (aprobado/fallido)
- Número de bugs
- Número de code smells
- Número de vulnerabilidades de seguridad
3. Lista los 5 problemas más críticos encontrados`;
await sbx.commands.run(
`echo '${prompt.replace(/'/g, "'\\''")}' | claude -p --dangerously-skip-permissions`,
{
timeoutMs: 0,
onStdout: console.log,
onStderr: console.log,
},
);
await sbx.kill();
}
testSonarQube().catch(console.error);Ejecuta el script:
npx tsx 04-test-sonarqube.tsCrea 04_test_sonarqube.py:
import os
import asyncio
from dotenv import load_dotenv
from e2b import AsyncSandbox
load_dotenv()
async def test_sonarqube():
print("Creando sandbox...\n")
sbx = await AsyncSandbox.beta_create(
envs={
"ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY"),
"GITHUB_TOKEN": os.getenv("GITHUB_TOKEN"),
"SONARQUBE_TOKEN": os.getenv("SONARQUBE_TOKEN"),
},
mcp={
"githubOfficial": {
"githubPersonalAccessToken": os.getenv("GITHUB_TOKEN"),
},
"sonarqube": {
"org": os.getenv("SONARQUBE_ORG"),
"token": os.getenv("SONARQUBE_TOKEN"),
"url": "https://sonarcloud.io",
},
},
)
mcp_url = sbx.beta_get_mcp_url()
mcp_token = await sbx.beta_get_mcp_token()
await asyncio.sleep(1)
await sbx.commands.run(
f'claude mcp add --transport http e2b-mcp-gateway {mcp_url} --header "Authorization: Bearer {mcp_token}"',
timeout=0,
on_stdout=print,
on_stderr=print,
)
print("\nAnalizando la calidad del código con SonarQube...\n")
prompt = """Usando las herramientas de MCP de SonarQube:
1. Lista todos los proyectos en mi organización
2. Para el primer proyecto, muestra:
- Estado del quality gate (aprobado/fallido)
- Número de bugs
- Número de code smells
- Número de vulnerabilidades de seguridad
3. Lista los 5 problemas más críticos encontrados"""
await sbx.commands.run(
f"echo '{prompt}' | claude -p --dangerously-skip-permissions",
timeout=0,
on_stdout=print,
on_stderr=print,
)
await sbx.kill()
if __name__ == "__main__":
asyncio.run(test_sonarqube())Ejecuta el script:
python 04_test_sonarqube.pyNoteEste script puede tardar unos minutos en ejecutarse.
Deberías ver a Claude mostrar los resultados del análisis de SonarQube:
Creando sandbox...
Analizando la calidad del código con SonarQube...
## Resultados del análisis de SonarQube
### 1. Proyectos en tu organización
Se encontró **1 proyecto**:
- **Nombre del proyecto**: proyecto-1
- **Clave del proyecto**: proyecto-testing
### 2. Análisis del proyecto
...
### 3. Los 5 problemas más críticos
Se encontró 1 problema en total (todos son code smells sin gravedad crítica o bloqueante):
1. **Gravedad: MAYOR** - test.js:2
- **Regla**: javascript:S1854
- **Mensaje**: Remove this useless assignment to variable "unusedVariable" (Elimina esta asignación inútil a la variable "unusedVariable")
- **Estado**: OPEN
**Resumen**: El proyecto goza de buena salud sin bugs ni vulnerabilidades detectadas.
Ahora puedes usar las herramientas de MCP de SonarQube para analizar la calidad del código mediante lenguaje natural. Puedes recuperar métricas de calidad, identificar problemas y entender qué código necesita corregirse.
Paso 5: Crea una rama y realiza cambios en el código
Ahora enseñemos a Claude a corregir código basándose en los problemas de calidad descubiertos por SonarQube.
Crea 05-fix-code-issue.ts:
import "dotenv/config";
import { Sandbox } from "e2b";
async function fixCodeIssue() {
console.log("Creando sandbox...\n");
const sbx = await Sandbox.betaCreate({
envs: {
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
GITHUB_TOKEN: process.env.GITHUB_TOKEN!,
SONARQUBE_TOKEN: process.env.SONARQUBE_TOKEN!,
},
mcp: {
githubOfficial: {
githubPersonalAccessToken: process.env.GITHUB_TOKEN!,
},
sonarqube: {
org: process.env.SONARQUBE_ORG!,
token: process.env.SONARQUBE_TOKEN!,
url: "https://sonarcloud.io",
},
},
});
const mcpUrl = sbx.betaGetMcpUrl();
const mcpToken = await sbx.betaGetMcpToken();
await new Promise((resolve) => setTimeout(resolve, 1000));
await sbx.commands.run(
`claude mcp add --transport http e2b-mcp-gateway ${mcpUrl} --header "Authorization: Bearer ${mcpToken}"`,
{ timeoutMs: 0, onStdout: console.log, onStderr: console.log },
);
const repoPath = `${process.env.GITHUB_OWNER}/${process.env.GITHUB_REPO}`;
const branchName = `quality-fix-${Date.now()}`;
console.log("\nCorrigiendo un problema de calidad de código...\n");
const prompt = `Usando las herramientas de MCP de GitHub y SonarQube:
1. Analiza la calidad del código en el repositorio "${repoPath}" con SonarQube
2. Encuentra UN problema sencillo que se pueda corregir con total seguridad (como una variable no utilizada o un code smell)
3. Crea una nueva rama llamada "${branchName}"
4. Lee el archivo que contiene el problema usando las herramientas de GitHub
5. Corrige el problema en el código
6. Confirma (commit) la corrección en la nueva rama con un mensaje de commit claro
Importante: Solo corrige problemas sobre los que tengas un 100% de seguridad. Explica qué estás corrigiendo y por qué.`;
await sbx.commands.run(
`echo '${prompt.replace(/'/g, "'\\''")}' | claude -p --dangerously-skip-permissions`,
{
timeoutMs: 0,
onStdout: console.log,
onStderr: console.log,
},
);
console.log(`\nRevisa tu repositorio para ver la rama: ${branchName}`);
await sbx.kill();
}
fixCodeIssue().catch(console.error);Ejecuta el script:
npx tsx 05-fix-code-issue.tsCrea 05_fix_code_issue.py:
import os
import asyncio
import time
from dotenv import load_dotenv
from e2b import AsyncSandbox
load_dotenv()
async def fix_code_issue():
print("Creando sandbox...\n")
sbx = await AsyncSandbox.beta_create(
envs={
"ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY"),
"GITHUB_TOKEN": os.getenv("GITHUB_TOKEN"),
"SONARQUBE_TOKEN": os.getenv("SONARQUBE_TOKEN"),
},
mcp={
"githubOfficial": {
"githubPersonalAccessToken": os.getenv("GITHUB_TOKEN"),
},
"sonarqube": {
"org": os.getenv("SONARQUBE_ORG"),
"token": os.getenv("SONARQUBE_TOKEN"),
"url": "https://sonarcloud.io",
},
},
)
mcp_url = sbx.beta_get_mcp_url()
mcp_token = await sbx.beta_get_mcp_token()
await asyncio.sleep(1)
await sbx.commands.run(
f'claude mcp add --transport http e2b-mcp-gateway {mcp_url} --header "Authorization: Bearer {mcp_token}"',
timeout=0,
on_stdout=print,
on_stderr=print,
)
repo_path = f"{os.getenv('GITHUB_OWNER')}/{os.getenv('GITHUB_REPO')}"
branch_name = f"quality-fix-{int(time.time() * 1000)}"
print("\nCorrigiendo un problema de calidad de código...\n")
prompt = f"""Usando las herramientas de MCP de GitHub y SonarQube:
1. Analiza la calidad del código en el repositorio "{repo_path}" con SonarQube
2. Encuentra UN problema sencillo que se pueda corregir con total seguridad (como una variable no utilizada o un code smell)
3. Crea una nueva rama llamada "{branch_name}"
4. Lee el archivo que contiene el problema usando las herramientas de GitHub
5. Corrige el problema en el código
6. Confirma (commit) la corrección en la nueva rama con un mensaje de commit claro
Importante: Solo corrige problemas sobre los que tengas un 100% de seguridad. Explica qué estás corrigiendo y por qué."""
await sbx.commands.run(
f"echo '{prompt}' | claude -p --dangerously-skip-permissions",
timeout=0,
on_stdout=print,
on_stderr=print,
)
print(f"\n Revisa tu repositorio para ver la rama: {branch_name}")
await sbx.kill()
if __name__ == "__main__":
asyncio.run(fix_code_issue())Ejecuta el script:
python 05_fix_code_issue.pyNoteEste script puede tardar unos minutos en ejecutarse.
Claude analizará tu repositorio y corregirá un problema de calidad del código:
Creando sandbox...
Corrigiendo un problema de calidad de código...
## ¡Tarea completada con éxito!
He analizado con éxito el repositorio y he corregido un problema de calidad de código. Esto es lo que hice:
### 1. Análisis
Encontré 1 problema de SonarQube en el repositorio `<tu-repositorio>`:
- **Variable no utilizada** (gravedad MINOR, línea 2)
- Asignación inútil (gravedad MAJOR, línea 2)
- Sugerencia de bucle for-of (gravedad MINOR, líneas 5-7)
### 2. Problema corregido
**Ubicación:** test.js:2
**Problema:** Declaración de variable no utilizada
**Regla de SonarQube:** javascript:S1481
**Qué estaba mal:** La línea `const unusedVariable = "this is not used";` declaraba una variable que nunca se utilizaba en ningún lugar de la función.
### 3. Por qué esta corrección es segura
- La variable solo se declaraba y asignaba, nunca se hacía referencia a ella.
- Eliminarla tiene un impacto nulo en el funcionamiento.
- Elimina código muerto y mejora la calidad del código.
- Este es un ejemplo de manual de un code smell que debe ser eliminado.
### 4. Cambios realizados
- Se creó la rama: `quality-fix-xxxxx`
- Se eliminó la declaración de la variable no utilizada
- Se realizó el commit con un mensaje claro que explica la corrección y hace referencia a la regla de SonarQube
**SHA del commit:** `xxxxxxxxxxxxxxxxxxxxxxxxx`
**Rama:** https://github.com/<org-github>/<tu-repositorio>/tree/quality-fix-xxxxx
¡La corrección está lista para revisión y puede ser integrada para mejorar la calidad del código del repositorio!
Ahora puedes usar las herramientas de MCP de GitHub y SonarQube en el mismo flujo de trabajo para leer archivos, realizar cambios en el código y confirmarlos.
Paso 6: Crea pull requests con control de calidad
Finalmente, construyamos el flujo de trabajo completo: analiza la calidad, corrige los problemas y crea una PR únicamente si se realizan mejoras.
Crea 06-quality-gated-pr.ts:
import "dotenv/config";
import { Sandbox } from "e2b";
async function qualityGatedPR() {
console.log(
"Creando sandbox para el flujo de trabajo de PR con control de calidad...\n",
);
const sbx = await Sandbox.betaCreate({
envs: {
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
GITHUB_TOKEN: process.env.GITHUB_TOKEN!,
SONARQUBE_TOKEN: process.env.SONARQUBE_TOKEN!,
},
mcp: {
githubOfficial: {
githubPersonalAccessToken: process.env.GITHUB_TOKEN!,
},
sonarqube: {
org: process.env.SONARQUBE_ORG!,
token: process.env.SONARQUBE_TOKEN!,
url: "https://sonarcloud.io",
},
},
});
const mcpUrl = sbx.betaGetMcpUrl();
const mcpToken = await sbx.betaGetMcpToken();
await new Promise((resolve) => setTimeout(resolve, 1000));
await sbx.commands.run(
`claude mcp add --transport http e2b-mcp-gateway ${mcpUrl} --header "Authorization: Bearer ${mcpToken}"`,
{ timeoutMs: 0, onStdout: console.log, onStderr: console.log },
);
const repoPath = `${process.env.GITHUB_OWNER}/${process.env.GITHUB_REPO}`;
const branchName = `quality-improvements-${Date.now()}`;
console.log(
"\nEjecutando el flujo de trabajo de PR con control de calidad...\n",
);
const prompt = `Eres un ingeniero de calidad de código. Usando las herramientas de MCP de GitHub y SonarQube:
PASO 1: ANÁLISIS
- Obtén el estado actual de la calidad del código de SonarQube para "${repoPath}"
- Registra el número actual de bugs, code smells y vulnerabilidades
- Identifica de 1 a 3 problemas que puedas corregir con seguridad
PASO 2: CORREGIR PROBLEMAS
- Crea la rama "${branchName}"
- Para cada problema que vayas a corregir:
* Lee el archivo que contiene el problema
* Realiza la corrección
* Confirma los cambios (commit) con un mensaje descriptivo
- Solo corrige problemas si tienes un 100% de seguridad de que la corrección es correcta
PASO 3: VERIFICACIÓN
- Tras tus correcciones, comprueba si las métricas de calidad mejorarían
- Calcula: ¿reduciría esto los bugs, smells o vulnerabilidades?
PASO 4: CONTROL DE CALIDAD (QUALITY GATE)
- Solo continúa si tus cambios mejoran la calidad
- Si la calidad no mejora, explica por qué y detén el proceso
PASO 5: CREAR PR (solo si pasa el control de calidad)
- Crea un pull request desde "${branchName}" hacia la rama main
- Título: "Mejoras de calidad: [describe qué has corregido]"
- La descripción debe incluir:
* Qué problemas has corregido
* Métricas de calidad antes y después
* Por qué estas correcciones mejoran la calidad del código
- Agrega un comentario con el análisis detallado de SonarQube
Sé minucioso y explica tus decisiones en cada paso.`;
await sbx.commands.run(
`echo '${prompt.replace(/'/g, "'\\''")}' | claude -p --dangerously-skip-permissions`,
{
timeoutMs: 0,
onStdout: console.log,
onStderr: console.log,
},
);
console.log(
`\n ¡Flujo de trabajo completado! Revisa ${repoPath} para ver la nueva pull request.`,
);
await sbx.kill();
}
qualityGatedPR().catch(console.error);Ejecuta el script:
npx tsx 06-quality-gated-pr.tsCrea 06_quality_gated_pr.py:
import os
import asyncio
import time
from dotenv import load_dotenv
from e2b import AsyncSandbox
load_dotenv()
async def quality_gated_pr():
print("Creando sandbox para el flujo de trabajo de PR con control de calidad...\n")
sbx = await AsyncSandbox.beta_create(
envs={
"ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY"),
"GITHUB_TOKEN": os.getenv("GITHUB_TOKEN"),
"SONARQUBE_TOKEN": os.getenv("SONARQUBE_TOKEN"),
},
mcp={
"githubOfficial": {
"githubPersonalAccessToken": os.getenv("GITHUB_TOKEN"),
},
"sonarqube": {
"org": os.getenv("SONARQUBE_ORG"),
"token": os.getenv("SONARQUBE_TOKEN"),
"url": "https://sonarcloud.io",
},
},
)
mcp_url = sbx.beta_get_mcp_url()
mcp_token = await sbx.beta_get_mcp_token()
await asyncio.sleep(1)
await sbx.commands.run(
f'claude mcp add --transport http e2b-mcp-gateway {mcp_url} --header "Authorization: Bearer ${mcp_token}"',
timeout=0,
on_stdout=print,
on_stderr=print,
)
repo_path = f"{os.getenv('GITHUB_OWNER')}/{os.getenv('GITHUB_REPO')}"
branch_name = f"quality-improvements-{int(time.time() * 1000)}"
print("\nEjecutando el flujo de trabajo de PR con control de calidad...\n")
prompt = f"""Eres un ingeniero de calidad de código. Usando las herramientas de MCP de GitHub y SonarQube:
PASO 1: ANÁLISIS
- Obtén el estado actual de la calidad del código de SonarQube para "{repo_path}"
- Registra el número actual de bugs, code smells y vulnerabilidades
- Identifica de 1 a 3 problemas que puedas corregir con seguridad
PASO 2: CORREGIR PROBLEMAS
- Crea la rama "${branch_name}"
- Para cada problema que vayas a corregir:
Lee el archivo que contiene el problema
Realiza la corrección
Confirma los cambios (commit) con un mensaje descriptivo
- Solo corrige problemas si tienes un 100 por ciento de seguridad de que la corrección es correcta
PASO 3: VERIFICACIÓN
- Tras tus correcciones, comprueba si las métricas de calidad mejorarían
- Calcula: ¿reduciría esto los bugs, smells o vulnerabilidades?
PASO 4: CONTROL DE CALIDAD (QUALITY GATE)
- Solo continúa si tus cambios mejoran la calidad
- Si la calidad no mejora, explica por qué y detén el proceso
PASO 5: CREAR PR (solo si pasa el control de calidad)
- Crea un pull request desde "${branch_name}" hacia la rama main
- Título: "Mejoras de calidad: [describe qué has corregido]"
- La descripción debe incluir:
Qué problemas has corregido
Métricas de calidad antes y después
Por qué estas correcciones mejoran la calidad del código
- Agrega un comentario con el análisis detallado de SonarQube
Sé minucioso y explica tus decisiones en cada paso."""
await sbx.commands.run(
f"echo '{prompt.replace(chr(39), chr(39) + chr(92) + chr(39) + chr(39))}' | claude -p --dangerously-skip-permissions",
timeout=0,
on_stdout=print,
on_stderr=print,
)
print(f"\n ¡Flujo de trabajo completado! Revisa {repo_path} para ver la nueva pull request.")
await sbx.kill()
if __name__ == "__main__":
asyncio.run(quality_gated_pr())Ejecuta el script:
python 06_quality_gated_pr.pyNoteEste script puede tardar unos minutos en ejecutarse.
Claude ejecutará todo el flujo de trabajo, creando una mejora de calidad y abriendo una PR en GitHub:
Creando sandbox para el flujo de trabajo de PR con control de calidad...
Ejecutando el flujo de trabajo de PR con control de calidad...
## ¡Completado - Corrección de calidad de código ejecutada con éxito!
### Resumen del trabajo completado
**Pull Request Creado:** https://github.com/<org-github>/<tu-repositorio>/pull/1
---
### PASO 1: ANÁLISIS
**Estado actual:**
- **Bugs:** 0
- **Vulnerabilidades:** 0
- **Code Smells:** 1
- **Líneas de código:** 12
- **Clasificaciones:** A (Fiabilidad, Seguridad, Mantenibilidad)
**Problemas identificados (todos en test.js):**
1. xxxxxxxxx - Declaración de variable no utilizada (MINOR)
---
### PASO 2: CORREGIR PROBLEMAS
**Rama creada:** `quality-improvements-xxxxxxxx`
**Cambios realizados:**
1. **Se eliminó la variable no utilizada** (línea 2) - Se eliminó código muerto que no tenía utilidad alguna.
2. **Se modernizó el patrón de bucle** (líneas 5-7) - Se convirtió `for (let i = 0; i < items.length; i++)` en `for (const item of items)`.
**Commit:** xxxxxxxxxx
---
### PASO 3: VERIFICACIÓN
**Impacto esperado:**
- Code Smells: 1 → 0 (reducción del 100%)
- Bugs: 0 → 0 (mantenido)
- Vulnerabilidades: 0 → 0 (mantenido)
- Todas las calificaciones de calidad se mantienen en A
---
### PASO 4: CONTROL DE CALIDAD APROBADO
**Criterios de decisión cumplidos:**
- ✅ Reduces los code smells en un 100%
- ✅ No se introducen nuevos bugs ni vulnerabilidades
- ✅ El código es más legible y mantenible
- ✅ Sigue las mejores prácticas modernas de JavaScript
- ✅ Todas las correcciones son refactorizaciones de bajo riesgo sin cambios de comportamiento
---
### PASO 5: CREAR PR
**Detalles del Pull Request:**
- **Número:** #1
- **Título:** Mejoras de calidad: Eliminar variable no utilizada y modernizar bucle for
- **Rama:** quality-improvements-xxxxxxxx → main
- **URL:** https://github.com/<org-github>/<tu-repositorio>/pull/1
**La PR incluye:**
- Descripción detallada con métricas antes y después
- Comentario con el análisis minucioso de SonarQube con el desglose de problemas
- Comparación de código que muestra las mejoras
- Tabla de métricas de calidad
¡El pull request ya está listo para revisión e integración!
Ahora has construido un flujo de trabajo completo de múltiples pasos con lógica condicional. Claude analiza la calidad con SonarQube, realiza correcciones utilizando las herramientas de GitHub, verifica las mejoras y crea una PR únicamente si la calidad realmente mejora.
Paso 7: Agrega manejo de errores
Los flujos de trabajo en producción necesitan manejo de errores. Hagamos que el flujo de trabajo sea más robusto.
Crea 07-robust-workflow.ts:
import "dotenv/config";
import { Sandbox } from "e2b";
async function robustWorkflow() {
let sbx: Sandbox | undefined;
try {
console.log("Creando sandbox...\n");
sbx = await Sandbox.betaCreate({
envs: {
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
GITHUB_TOKEN: process.env.GITHUB_TOKEN!,
SONARQUBE_TOKEN: process.env.SONARQUBE_TOKEN!,
},
mcp: {
githubOfficial: {
githubPersonalAccessToken: process.env.GITHUB_TOKEN!,
},
sonarqube: {
org: process.env.SONARQUBE_ORG!,
token: process.env.SONARQUBE_TOKEN!,
url: "https://sonarcloud.io",
},
},
});
const mcpUrl = sbx.betaGetMcpUrl();
const mcpToken = await sbx.betaGetMcpToken();
await new Promise((resolve) => setTimeout(resolve, 1000));
await sbx.commands.run(
`claude mcp add --transport http e2b-mcp-gateway ${mcpUrl} --header "Authorization: Bearer ${mcpToken}"`,
{ timeoutMs: 0, onStdout: console.log, onStderr: console.log },
);
const repoPath = `${process.env.GITHUB_OWNER}/${process.env.GITHUB_REPO}`;
console.log("\nEjecutando flujo de trabajo con manejo de errores...\n");
const prompt = `Ejecuta un flujo de trabajo de mejora de calidad para "${repoPath}".
REGLAS DE MANEJO DE ERRORES:
1. Si SonarQube es inaccesible, explica el error y detén el proceso de forma controlada
2. Si falla la API de GitHub, reintenta una vez, luego explica y detén el proceso
3. Si no se encuentran problemas corregibles, explica por qué y sal (esto no es un error)
4. Si las modificaciones de archivos fallan, explica qué archivo y por qué
5. En cada paso, comprueba si hay errores antes de continuar
Ejecuta el flujo de trabajo y maneja cualquier error que encuentres de manera profesional.`;
await sbx.commands.run(
`echo '${prompt.replace(/'/g, "'\\''")}' | claude -p --dangerously-skip-permissions`,
{
timeoutMs: 0,
onStdout: console.log,
onStderr: console.log,
},
);
console.log("\n Flujo de trabajo completado");
} catch (error) {
const err = error as Error;
console.error("\n El flujo de trabajo falló:", err.message);
if (err.message.includes("403")) {
console.error(
"\n Comprueba que tu cuenta de E2B tenga acceso a la pasarela MCP",
);
} else if (err.message.includes("401")) {
console.error("\n Comprueba que tus tokens de API sean válidos");
} else if (err.message.includes("Credit balance")) {
console.error("\n Comprueba el saldo de créditos de tu API de Anthropic");
}
process.exit(1);
} finally {
if (sbx) {
console.log("\n Limpiando sandbox...");
await sbx.kill();
}
}
}
robustWorkflow().catch(console.error);Ejecuta el script:
npx tsx 07-robust-workflow.tsCrea 07_robust_workflow.py:
import os
import asyncio
import sys
from dotenv import load_dotenv
from e2b import AsyncSandbox
load_dotenv()
async def robust_workflow():
sbx = None
try:
print("Creando sandbox...\n")
sbx = await AsyncSandbox.beta_create(
envs={
"ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY"),
"GITHUB_TOKEN": os.getenv("GITHUB_TOKEN"),
"SONARQUBE_TOKEN": os.getenv("SONARQUBE_TOKEN"),
},
mcp={
"githubOfficial": {
"githubPersonalAccessToken": os.getenv("GITHUB_TOKEN"),
},
"sonarqube": {
"org": os.getenv("SONARQUBE_ORG"),
"token": os.getenv("SONARQUBE_TOKEN"),
"url": "https://sonarcloud.io",
},
},
)
mcp_url = sbx.beta_get_mcp_url()
mcp_token = await sbx.beta_get_mcp_token()
await asyncio.sleep(1)
await sbx.commands.run(
f'claude mcp add --transport http e2b-mcp-gateway {mcp_url} --header "Authorization: Bearer {mcp_token}"',
timeout=0,
on_stdout=print,
on_stderr=print,
)
repo_path = f"{os.getenv('GITHUB_OWNER')}/{os.getenv('GITHUB_REPO')}"
print("\nEjecutando flujo de trabajo con manejo de errores...\n")
prompt = f"""Ejecuta un flujo de trabajo de mejora de calidad para "{repo_path}".
REGLAS DE MANEJO DE ERRORES:
1. Si SonarQube es inaccesible, explica el error y detén el proceso de forma controlada
2. Si falla la API de GitHub, reintenta una vez, luego explica y detén el proceso
3. Si no se encuentran problemas corregibles, explica por qué y sal (esto no es un error)
4. Si las modificaciones de archivos fallan, explica qué archivo y por qué
5. En cada paso, comprueba si hay errores antes de continuar
Ejecuta el flujo de trabajo y maneja cualquier error que encuentres de manera profesional."""
await sbx.commands.run(
f"echo '{prompt}' | claude -p --dangerously-skip-permissions",
timeout=0,
on_stdout=print,
on_stderr=print,
)
print("\n Flujo de trabajo completado")
except Exception as error:
print(f"\n✗ El flujo de trabajo falló: {str(error)}")
error_msg = str(error)
if "403" in error_msg:
print("\n Comprueba que tu cuenta de E2B tenga acceso a la pasarela MCP")
elif "401" in error_msg:
print("\n Comprueba que tus tokens de API sean válidos")
elif "Credit balance" in error_msg:
print("\n Comprueba el saldo de créditos de tu API de Anthropic")
sys.exit(1)
finally:
if sbx:
print("\n Limpiando sandbox...")
await sbx.kill()
if __name__ == "__main__":
asyncio.run(robust_workflow())Ejecuta el script:
python 07_robust_workflow.pyClaude ejecutará todo el flujo de trabajo y, si encuentra algún error, responderá con mensajes de error robustos.
Próximos pasos
En la siguiente sección, personalizarás tu flujo de trabajo según tus necesidades.