Skip to main content
Glama
JuanPQ26

WorkItems DevOps MCP Server

by JuanPQ26
README.md
# 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

```bash
# 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:

```env
AZURE_DEVOPS_ACCESS_TOKEN=tu_personal_access_token
AZURE_DEVOPS_PROJECT=nombre_del_proyecto
AZURE_DEVOPS_ORGANIZATION=nombre_de_la_organizacion
```

### 3. Ejecución

```bash
# 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
```python
# 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
```python
# 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
```python
# Obtener detalles de múltiples work items
get_workitems_details_by_ids("12345,67890")
```

### Ejemplo 4: Actualizar fechas planeadas
```python
# 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
```python
# 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

1. **Definir función en `services/workitems.py`**:
```python
async def mi_nueva_funcion(parametro: str) -> dict:
    # Lógica de negocio
    return resultado
```

2. **Exponer como herramienta MCP en `server.py`**:
```python
@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

```toml
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:
```json
{
  "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
```bash
# 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
```bash
# 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
```bash
# Ejecutar servidor para probar
python server.py
```

### Paso 4: Integración con Cliente IA

#### Para Claude Desktop:
```json
// 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:
```python
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
```python
# 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
```python
# 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
```python
# 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
```python
# 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:

1. **Definir en `services/workitems.py`**:
```python
async def get_workitems_by_sprint(sprint_name: str) -> list[str]:
    """Nueva función para obtener work items por sprint"""
    # Implementación
    pass
```

2. **Exponer en `server.py`**:
```python
@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:
```python
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:
```python
# 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:
```python
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:
```bash
# Ejecutar servidor en background
nohup python server.py &
```

#### Para Contenedor Docker:
```dockerfile
FROM python:3.13-slim
WORKDIR /app
COPY . .
RUN pip install uv && uv sync
CMD ["python", "server.py"]
```

```bash
# Build y run
docker build -t workitems-mcp .
docker run -d --env-file .env workitems-mcp
```

#### Para Servidor:
```bash
# 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

1. **Usa el entorno correcto**: Siempre activa el venv antes de trabajar
2. **Variables de entorno**: Nunca hardcodees tokens en el código
3. **Manejo de errores**: Azure DevOps puede devolver diferentes códigos de error
4. **Rate limiting**: Considera implementar rate limiting para evitar excesos
5. **Caching**: Para consultas frecuentes, considera implementar cache
6. **Logging**: Usa logs para debugging, pero no loggees información sensible
7. **Operaciones en lote**: Aprovecha las funciones de actualización masiva para eficiencia
8. **Formateo inteligente**: Utiliza las funciones de formateo para presentar datos de manera legible
9. **Testing**: Crea tests unitarios para tus nuevas funcionalidades

### 🔗 Recursos Útiles

- [Azure DevOps REST API](https://docs.microsoft.com/en-us/rest/api/azure/devops/)
- [Model Context Protocol Docs](https://modelcontextprotocol.io/)
- [WIQL Reference](https://docs.microsoft.com/en-us/azure/devops/boards/queries/wiql-syntax)
- [FastMCP Documentation](https://github.com/pydantic/fastmcp)

Maintenance

ActivityInactive
ResponsivenessNo issues