131 lines
4.3 KiB
Python
131 lines
4.3 KiB
Python
# kanboard_mcp.py
|
||
"""
|
||
🚀 Servidor FastMCP para controlar Kanboard desde un LLM.
|
||
|
||
Este módulo expone las funciones del paquete `kanboard_utils`
|
||
como herramientas del protocolo MCP (Model Context Protocol),
|
||
permitiendo a modelos de lenguaje (LLMs) listar, crear, mover
|
||
y editar tareas en Kanboard de forma segura y programática.
|
||
|
||
Requisitos:
|
||
uv add fastmcp requests python-dotenv
|
||
"""
|
||
|
||
import os
|
||
from fastmcp import FastMCP
|
||
from kanboard_utils import (
|
||
listar_proyectos,
|
||
listar_usuarios,
|
||
listar_tareas,
|
||
listar_subtareas,
|
||
listar_tareas_por_columna,
|
||
mover_tarea_columna,
|
||
crear_tarea,
|
||
editar_tarea,
|
||
)
|
||
|
||
# ========================
|
||
# ⚙️ Configuración global
|
||
# ========================
|
||
|
||
# Carga las variables de entorno automáticamente
|
||
# (útil si usas un archivo .env con los valores)
|
||
from dotenv import load_dotenv
|
||
load_dotenv()
|
||
|
||
# Lee las credenciales de Kanboard desde variables de entorno
|
||
API_URL = os.getenv("KANBOARD_API_URL", "http://localhost:8080/jsonrpc.php")
|
||
USER = os.getenv("KANBOARD_USER", "jsonrpc")
|
||
TOKEN = os.getenv("KANBOARD_TOKEN", "792d8fdd6cbf69b3a32d800beaf48b958e4490dd9185c72c06c56061a591")
|
||
|
||
# ========================
|
||
# 🧠 Inicializa el servidor
|
||
# ========================
|
||
mcp = FastMCP(
|
||
"Kanboard Controller",
|
||
instructions="""
|
||
Controlador MCP para Kanboard que permite a un LLM gestionar tareas,
|
||
proyectos y usuarios de un tablero Kanboard mediante JSON-RPC.
|
||
"""
|
||
)
|
||
|
||
# =====================================================
|
||
# 🧩 Herramientas disponibles para el agente LLM
|
||
# =====================================================
|
||
|
||
@mcp.tool
|
||
def list_projects() -> list[dict]:
|
||
"""📁 Listar todos los proyectos de Kanboard."""
|
||
return listar_proyectos(API_URL, USER, TOKEN)
|
||
|
||
|
||
@mcp.tool
|
||
def list_users() -> list[dict]:
|
||
"""👥 Listar todos los usuarios disponibles en Kanboard."""
|
||
return listar_usuarios(API_URL, USER, TOKEN)
|
||
|
||
|
||
|
||
@mcp.tool
|
||
def list_tasks(project_id: int) -> list[str]:
|
||
"""
|
||
🗂️ Listar todas las tareas de un proyecto (solo nombres).
|
||
|
||
Devuelve una lista simple de títulos de tareas, sin metadatos adicionales.
|
||
Esto simplifica el contexto para modelos de lenguaje.
|
||
"""
|
||
tareas = listar_tareas(API_URL, USER, TOKEN, project_id)
|
||
|
||
# 🧹 Extrae solo los títulos (ignorando otros campos)
|
||
nombres = [t["title"] for t in tareas if "title" in t]
|
||
|
||
# 🔢 Devuelve lista simple de strings
|
||
return nombres
|
||
|
||
|
||
@mcp.tool
|
||
def list_subtasks(task_id: int) -> list[dict]:
|
||
"""📋 Listar las subtareas de una tarea específica."""
|
||
return listar_subtareas(API_URL, USER, TOKEN, task_id)
|
||
|
||
|
||
@mcp.tool
|
||
def list_tasks_by_column(project_id: int) -> dict:
|
||
"""🧩 Agrupar las tareas por columna del tablero Kanboard."""
|
||
return listar_tareas_por_columna(API_URL, USER, TOKEN, project_id)
|
||
|
||
|
||
@mcp.tool
|
||
def move_task(project_id: int, task_id: int, column_id: int,
|
||
position: int = 1, swimlane_id: int = 0) -> bool:
|
||
"""🔄 Mover una tarea entre columnas del tablero."""
|
||
return mover_tarea_columna(API_URL, USER, TOKEN, project_id, task_id, column_id, position, swimlane_id)
|
||
|
||
|
||
@mcp.tool
|
||
def create_task(project_id: int, titulo: str, descripcion: str = "",
|
||
swimlane_id: int | None = None, assignee_id: int | None = None,
|
||
tags: list[str] | None = None, priority: int | None = None) -> dict:
|
||
"""➕ Crear una nueva tarea en un proyecto Kanboard."""
|
||
return crear_tarea(API_URL, USER, TOKEN, project_id, titulo, descripcion,
|
||
swimlane_id, assignee_id, tags, priority)
|
||
|
||
|
||
@mcp.tool
|
||
def edit_task(task_id: int, titulo: str | None = None, descripcion: str | None = None,
|
||
swimlane_id: int | None = None, assignee_id: int | None = None,
|
||
tags: list[str] | None = None, priority: int | None = None) -> dict:
|
||
"""✏️ Editar una tarea existente en Kanboard."""
|
||
return editar_tarea(API_URL, USER, TOKEN, task_id, titulo, descripcion,
|
||
swimlane_id, assignee_id, tags, priority)
|
||
|
||
|
||
# =====================================================
|
||
# 🚀 Punto de entrada principal del servidor FastMCP
|
||
# =====================================================
|
||
if __name__ == "__main__":
|
||
print("✅ Kanboard MCP listo y conectado con:")
|
||
print(f" 🌐 API_URL: {API_URL}")
|
||
print(f" 👤 Usuario: {USER}")
|
||
mcp.run()
|