WorkItems DevOps MCP Server
Un servidor Model Context Protocol (MCP) que proporciona herramientas para interactuar con Azure DevOps Work Items desde aplicaciones de IA/LLM.
🎯 Propósito
Este proyecto permite que modelos de lenguaje (LLMs) y aplicaciones de IA interactúen directamente con Azure DevOps para:
- Consultar work items asignados al usuario
- Filtrar work items por criterios específicos y fechas
- Obtener detalles completos de work items con formateo inteligente
- Gestionar tipos de work items y sus estados
- Actualizar estados, fechas planeadas y esfuerzo real de work items
- Modificar descripciones y agregar comentarios
- Operaciones en lote para múltiples work items
🏗️ Arquitectura
workitems_devops_mcp/
├── server.py # Servidor MCP con herramientas expuestas
├── main.py # Punto de entrada principal
├── settings.py # Configuración y variables de entorno
├── services/
│ └── workitems.py # Lógica de negocio para Azure DevOps API
└── utils/
├── http_client.py # Cliente HTTP para Azure DevOps
└── formatters.py # Formateadores de respuestas
🚀 Inicio Rápido
Prerrequisitos
- Python 3.13+
- Cuenta de Azure DevOps con acceso al proyecto
- Personal Access Token (PAT) de Azure DevOps
1. Instalación
# Clonar el repositorio
git clone <tu-repo>
cd workitems_devops_mcp
# Instalar dependencias
uv sync
2. Configuración
Crear un archivo .env en la raíz del proyecto:
AZURE_DEVOPS_ACCESS_TOKEN=tu_personal_access_token
AZURE_DEVOPS_PROJECT=nombre_del_proyecto
AZURE_DEVOPS_ORGANIZATION=nombre_de_la_organizacion
3. Ejecución
# Ejecutar el servidor MCP
python server.py
# O ejecutar el main básico
python main.py
🛠️ Herramientas Disponibles
El servidor MCP expone las siguientes herramientas:
🆕 Nuevas Funcionalidades
Actualizaciones recientes incluyen:
- ✅ Actualización de fechas planeadas (individual y en lote)
- ✅ Gestión de esfuerzo real con formateo inteligente
- ✅ Modificación de descripciones con soporte HTML
- ✅ Sistema de comentarios para seguimiento
- ✅ Formateo mejorado de fechas y esfuerzo
📋 Consulta de Work Items
| Herramienta | Descripción | Parámetros |
|---|---|---|
get_workitems_ids_assigned_to_user | Obtiene IDs de work items asignados al usuario | Ninguno |
get_workitems_ids_assigned_to_user_by | Filtra work items por criterios personalizados | columns_where: str |
get_workitems_ids_assigned_to_user_by_planned_date | Filtra por fecha de inicio planeada | planned_date: str |
get_workitems_details_by_ids | Obtiene detalles completos de work items | workitems_ids: str |
📊 Gestión de Tipos y Estados
| Herramienta | Descripción | Parámetros |
|---|---|---|
get_all_workitems_types | Lista todos los tipos de work items | Ninguno |
get_workitem_type_by_name | Obtiene un tipo específico por nombre | name: str |
get_workitem_type_states | Lista estados de un tipo de work item | workitem_type_name: str |
get_workitem_transitions_allowed | Obtiene transiciones permitidas | workitem_type_name: str, workitem_state_name: str |
✏️ Actualización
| Herramienta | Descripción | Parámetros |
|---|---|---|
update_workitem_state | Actualiza el estado de un work item | workitem_id: str, workitem_state_name: str |
update_workitem_planned_date | Actualiza la fecha planeada de un work item | workitem_id: str, planned_date: str |
update_workitem_real_effort | Actualiza el esfuerzo real de un work item | workitem_id: str, real_effort: str |
update_workitem_description | Actualiza la descripción de un work item | workitem_id: str, description: str |
update_workitems_planned_date | Actualiza la fecha planeada de múltiples work items | workitems_ids: str, planned_date: str |
add_workitem_comment | Agrega un comentario a un work item | workitem_id: str, comment: str |
💡 Ejemplos de Uso
Ejemplo 1: Obtener work items del día
# Usar la herramienta con fecha específica
get_workitems_ids_assigned_to_user_by_planned_date("2025-01-02")
# Resultado: "Workitems ids found: 12345,67890"
Ejemplo 2: Filtrar por criterios personalizados
# Filtrar por título y prioridad
get_workitems_ids_assigned_to_user_by("System.Title CONTAINS 'Backend' AND Microsoft.VSTS.Common.Priority = 1")
Ejemplo 3: Obtener detalles completos
# Obtener detalles de múltiples work items
get_workitems_details_by_ids("12345,67890")
Ejemplo 4: Actualizar fechas planeadas
# Actualizar fecha planeada de un work item
update_workitem_planned_date("12345", "2025-01-15T00:00:00Z")
# Actualizar fecha planeada de múltiples work items
update_workitems_planned_date("12345,67890", "2025-01-15T00:00:00Z")
Ejemplo 5: Gestionar esfuerzo y comentarios
# Actualizar esfuerzo real de un work item
update_workitem_real_effort("12345", "2.5")
# Agregar comentario a un work item
add_workitem_comment("12345", "Trabajo completado según especificaciones")
🔧 Configuración Avanzada
Variables de Entorno
| Variable | Descripción | Ejemplo |
|---|---|---|
AZURE_DEVOPS_ACCESS_TOKEN | Token de acceso personal | ghp_xxxxxxxxxxxxxxxxxxxx |
AZURE_DEVOPS_PROJECT | Nombre del proyecto | MiProyecto |
AZURE_DEVOPS_ORGANIZATION | Nombre de la organización | miempresa |
Configuración de API
- Versión de API: 7.0 (configurable en
settings.py) - User-Agent:
workitems-devops-mcp/1.0 - Autenticación: Basic Auth con PAT
🏃♂️ Desarrollo
Estructura del Código
server.py
- Define las herramientas MCP usando decoradores
@mcp.tool - Maneja la lógica de presentación y formateo de respuestas
- Punto de entrada para el servidor MCP
services/workitems.py
- Contiene toda la lógica de negocio para Azure DevOps API
- Funciones para consultas WIQL (Work Item Query Language)
- Gestión de tipos, estados y transiciones
utils/http_client.py
- Cliente HTTP asíncrono usando
httpx - Maneja autenticación y headers
- Métodos para GET, POST y PATCH
utils/formatters.py
- Formatea respuestas para presentación en español
- Convierte datos de API a formato legible
- Maneja fechas, esfuerzo y estados
- Incluye funciones especializadas para formateo de fechas ISO y conversión de esfuerzo a horas/minutos
Agregar Nuevas Herramientas
- Definir función en
services/workitems.py:
async def mi_nueva_funcion(parametro: str) -> dict:
# Lógica de negocio
return resultado
- Exponer como herramienta MCP en
server.py:
@mcp.tool("mi_nueva_herramienta")
async def mi_nueva_herramienta(parametro: str):
"""Descripción de la herramienta"""
resultado = await workitems.mi_nueva_funcion(parametro)
return formato_resultado(resultado)
📦 Dependencias
dependencies = [
"httpx>=0.28.1", # Cliente HTTP asíncrono
"mcp[cli]>=1.10.1", # Model Context Protocol
"pydantic-settings>=2.10.1", # Gestión de configuración
"python-dotenv>=1.1.1", # Variables de entorno
]
🤝 Integración con Aplicaciones IA
Este servidor MCP puede integrarse con:
- Claude Desktop: Agregar como servidor MCP en configuración
- Aplicaciones personales: Usar como cliente MCP
- Pipelines CI/CD: Automatización de work items
- Chatbots: Consulta y actualización de work items
Ejemplo de configuración para Claude Desktop:
{
"mcpServers": {
"workitems-devops": {
"command": "python",
"args": ["path/to/server.py"],
"env": {
"AZURE_DEVOPS_ACCESS_TOKEN": "tu_token"
}
}
}
}
🚨 Consideraciones de Seguridad
- ⚠️ Nunca commitear tokens: Usar siempre variables de entorno
- 🔒 Tokens con permisos mínimos: Solo Work Items (lectura/escritura)
- 🕐 Rotación de tokens: Renovar PATs periódicamente
- 📝 Logs: No loggear información sensible
🐛 Solución de Problemas
Error: "Workitems not found"
- Verificar IDs de work items válidos
- Confirmar permisos en Azure DevOps
Error de autenticación
- Validar PAT en Azure DevOps
- Verificar variables de entorno
Error de conexión
- Confirmar URL de organización/proyecto
- Verificar conectividad de red
Desarrollado con ❤️ para integración Azure DevOps + IA
📚 Guía Paso a Paso para Desarrolladores
Paso 1: Configuración Inicial
# 1. Clonar y navegar al proyecto
git clone <tu-repositorio>
cd workitems_devops_mcp
# 2. Crear entorno virtual y activar
python -m venv venv
source venv/bin/activate # Linux/Mac
# o
venv\Scripts\activate # Windows
# 3. Instalar dependencias
uv sync
# o si no tienes uv:
pip install -r requirements.txt
Paso 2: Configuración Azure DevOps
# 1. Crear archivo .env
touch .env
# 2. Agregar configuración (editar con tu editor favorito)
echo "AZURE_DEVOPS_ACCESS_TOKEN=tu_token_aqui" >> .env
echo "AZURE_DEVOPS_PROJECT=tu_proyecto" >> .env
echo "AZURE_DEVOPS_ORGANIZATION=tu_organizacion" >> .env
Paso 3: Verificar Conexión
# Ejecutar servidor para probar
python server.py
Paso 4: Integración con Cliente IA
Para Claude Desktop:
// Agregar a ~/.config/claude/claude_desktop_config.json
{
"mcpServers": {
"workitems-devops": {
"command": "python",
"args": ["/ruta/completa/al/servidor/server.py"],
"env": {
"AZURE_DEVOPS_ACCESS_TOKEN": "tu_token",
"AZURE_DEVOPS_PROJECT": "tu_proyecto",
"AZURE_DEVOPS_ORGANIZATION": "tu_organizacion"
}
}
}
}
Para Desarrollo Personalizado:
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def main():
server_params = StdioServerParameters(
command="python",
args=["server.py"],
env={
"AZURE_DEVOPS_ACCESS_TOKEN": "tu_token",
# ... más variables
}
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# Usar herramientas MCP
result = await session.call_tool(
"get_workitems_ids_assigned_to_user",
{}
)
print(result)
asyncio.run(main())
Paso 5: Casos de Uso Comunes
Caso 1: Consulta Matutina de Work Items
# 1. Obtener work items del día
work_items = get_workitems_ids_assigned_to_user_by_planned_date("2025-01-02")
# 2. Obtener detalles
details = get_workitems_details_by_ids(work_items)
Caso 2: Gestión de Estados y Actualizaciones
# 1. Verificar estados disponibles
states = get_workitem_type_states("Task")
# 2. Verificar transiciones permitidas
transitions = get_workitem_transitions_allowed("Task", "To Do")
# 3. Actualizar estado
update_workitem_state("12345", "In Progress")
# 4. Actualizar fecha planeada y esfuerzo
update_workitem_planned_date("12345", "2025-01-20T08:00:00Z")
update_workitem_real_effort("12345", "3.5")
# 5. Agregar comentario con el progreso
add_workitem_comment("12345", "Actualizado el estado y programado para completar el 20 de enero")
Caso 3: Filtros Avanzados
# Filtrar por múltiples criterios
filtered = get_workitems_ids_assigned_to_user_by(
"System.WorkItemType = 'Bug' AND Microsoft.VSTS.Common.Priority <= 2"
)
Caso 4: Operaciones en Lote y Gestión Avanzada
# 1. Obtener work items de una fecha específica
workitems = get_workitems_ids_assigned_to_user_by_planned_date("2025-01-15")
# 2. Actualizar fecha planeada de múltiples work items
update_workitems_planned_date(workitems, "2025-01-20T08:00:00Z")
# 3. Actualizar descripción con HTML
update_workitem_description("12345",
"<b>Actualización:</b><br/><ul><li>Cambio de fecha</li><li>Ajuste de prioridad</li></ul>")
# 4. Agregar comentario de seguimiento
add_workitem_comment("12345", "Reprogramado debido a dependencias externas")
Paso 6: Personalización y Extensión
Agregar Nueva Herramienta:
- Definir en
services/workitems.py:
async def get_workitems_by_sprint(sprint_name: str) -> list[str]:
"""Nueva función para obtener work items por sprint"""
# Implementación
pass
- Exponer en
server.py:
@mcp.tool("get_workitems_by_sprint")
async def get_workitems_by_sprint(sprint_name: str):
"""Obtiene work items de un sprint específico"""
result = await workitems.get_workitems_by_sprint(sprint_name)
return format_result(result)
Modificar Formateo:
Editar utils/formatters.py para cambiar cómo se presentan los datos:
def format_workitem(workitem: dict) -> str:
# Personalizar formato de salida
return f"Mi formato personalizado: {workitem}"
def format_effort(effort: str) -> str:
# Formatear esfuerzo en formato personalizado
hours = int(float(effort))
minutes = int((float(effort) - hours) * 60)
return f"{hours} horas {minutes} minutos"
Paso 7: Testing y Debugging
Probar Herramientas Manualmente:
# Crear script de prueba
import asyncio
from services.workitems import (
get_workitems_ids_assigned_to_user,
update_workitem_planned_date,
add_workitem_comment
)
async def test():
# Probar consulta básica
result = await get_workitems_ids_assigned_to_user()
print(f"Work items encontrados: {result}")
# Probar actualización de fecha
if result:
update_result = await update_workitem_planned_date(result[0], "2025-01-15T08:00:00Z")
print(f"Fecha actualizada: {update_result}")
# Probar agregar comentario
comment_result = await add_workitem_comment(result[0], "Prueba de comentario")
print(f"Comentario agregado: {comment_result}")
asyncio.run(test())
Debug con Logs:
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
# Agregar logs en tus funciones
logger.debug(f"Calling Azure DevOps API: {url}")
Paso 8: Despliegue
Para Uso Local:
# Ejecutar servidor en background
nohup python server.py &
Para Contenedor Docker:
FROM python:3.13-slim
WORKDIR /app
COPY . .
RUN pip install uv && uv sync
CMD ["python", "server.py"]
# Build y run
docker build -t workitems-mcp .
docker run -d --env-file .env workitems-mcp
Para Servidor:
# Usando systemd (Linux)
sudo tee /etc/systemd/system/workitems-mcp.service << EOF
[Unit]
Description=WorkItems MCP Server
After=network.target
[Service]
Type=simple
User=tu_usuario
WorkingDirectory=/ruta/al/proyecto
ExecStart=/ruta/al/venv/bin/python server.py
EnvironmentFile=/ruta/al/.env
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable workitems-mcp
sudo systemctl start workitems-mcp
🎯 Tips para Desarrolladores
- Usa el entorno correcto: Siempre activa el venv antes de trabajar
- Variables de entorno: Nunca hardcodees tokens en el código
- Manejo de errores: Azure DevOps puede devolver diferentes códigos de error
- Rate limiting: Considera implementar rate limiting para evitar excesos
- Caching: Para consultas frecuentes, considera implementar cache
- Logging: Usa logs para debugging, pero no loggees información sensible
- Operaciones en lote: Aprovecha las funciones de actualización masiva para eficiencia
- Formateo inteligente: Utiliza las funciones de formateo para presentar datos de manera legible
- Testing: Crea tests unitarios para tus nuevas funcionalidades
