configuracion de entorno de desarrollo
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-09-02
|
||||
@@ -0,0 +1,89 @@
|
||||
# Design: create-outline-mcp-server
|
||||
|
||||
## Context
|
||||
|
||||
El repositorio está vacío: el proyecto `outline-mcp` se construye desde cero. Es un servidor MCP (Model Context Protocol) en Go que actúa como puente entre clientes de IA y una instancia self-hosted de Outline. Restricciones clave:
|
||||
|
||||
- El desarrollo se realiza dentro de un contenedor (no se requiere Go local); por eso el primer entregable es el devcontainer.
|
||||
- La distribución se realiza mediante releases binarios publicados en Gitea (no hay registry de contenedores para el binario final).
|
||||
- El binario debe ser capaz de actualizarse a sí mismo desde la propia instancia de Gitea.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- Servidor MCP funcional con transporte stdio y 4 herramientas sobre la API de Outline.
|
||||
- Distribución reproducible: pipeline de Gitea Actions que publica binarios estáticos multi-plataforma.
|
||||
- Auto-update del binario sin intervención manual (descarga + `selfupdate.Apply`).
|
||||
- Entorno de desarrollo reproducible en contenedor con tooling de Go preconfigurado.
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- Transporte HTTP/SSE del servidor MCP (solo stdio en esta iteración).
|
||||
- Gestión avanzada de Outline (actualizar/borrar documentos, permisos, comentarios, attachments).
|
||||
- Firma de binarios / notarización.
|
||||
- Suite de tests de integración contra Outline real.
|
||||
|
||||
## Decisions
|
||||
|
||||
### D1: SDK de MCP — `github.com/mark3labs/mcp-go`
|
||||
|
||||
- **Elección**: usar `mcp-go` (paquetes `mcp` y `server`) con su `server.NewMCPServer` y transporte `ServeStdio`.
|
||||
- **Alternativa**: implementar el protocolo JSON-RPC manualmente. Se descarta por coste y riesgo; el SDK ya resuelve handshake, esquemas de herramientas y serialización.
|
||||
- **Nota**: `mcp-go` permite declarar esquemas de entrada tipados (`mcp.WithString(...)`, `mcp.Required()`) que se traducen a JSON Schema para el cliente.
|
||||
|
||||
### D2: Arquitectura de un solo archivo (`main.go`)
|
||||
|
||||
- **Elección**: mantener todo el código en `main.go` (CLI, cliente HTTP, herramientas, auto-update) con structs y funciones bien delimitados.
|
||||
- **Alternativa**: dividir en paquetes (`internal/outline`, `internal/updater`). Se descarta por ahora: el alcance es pequeño y un solo archivo facilita el bootstrap; la extracción a paquetes queda como refactor futuro sin impacto en specs.
|
||||
|
||||
### D3: Configuración por variables de entorno
|
||||
|
||||
- **Elección**: `OUTLINE_URL` y `OUTLINE_API_KEY` se leen en runtime al construir `OutlineClient`; los errores de configuración se devuelven como resultado MCP de error (no panic).
|
||||
- **Alternativa**: flags de línea de comandos o archivo de config. Se descarta: los clientes MCP (ej. Claude Desktop, opencode) inyectan `env` por proceso, por lo que el entorno es el canal natural.
|
||||
|
||||
### D4: Auto-update con `minio/selfupdate` + API de releases de Gitea
|
||||
|
||||
- **Elección**:
|
||||
1. `GET {GiteaURL}/api/v1/repos/{RepoOwner}/{RepoName}/releases/latest` para obtener tag y assets.
|
||||
2. Comparación semver simple: si el tag es igual o superior a `Version`, no se hace nada. Los tags siguen el formato `vX.Y.Z`; el prefijo `v` se recorta antes de comparar. La comparación se realiza parseando los tres componentes numéricos (no se introducirá una librería semver externa para mantener las dependencias mínimas).
|
||||
3. Selección de asset por convención de nombres `<name>_<GOOS>_<GOARCH>[.exe]` (ej. `outline-mcp_darwin_arm64`), filtrando con `runtime.GOOS`/`runtime.GOARCH`.
|
||||
4. Descarga del asset y aplicación con `selfupdate.Apply` (que reemplaza atómicamente el binario y respalda el antiguo en `.old`).
|
||||
- **Alternativa**: librería `go-selfupdate` (creativeprojects) con detección de assets automática. Se descarta: está orientada a GitHub y añade complejidad; la API de Gitea es compatible con el flujo simple de 4 pasos.
|
||||
- **Riesgo asumido**: la convención de nombres de assets es un contrato implícito entre el pipeline y el updater; se documenta en el pipeline.
|
||||
|
||||
### D5: Convención de nombres de assets
|
||||
|
||||
- **Elección**: el pipeline nombrará los binarios como `outline-mcp_{GOOS}_{GOARCH}` (con `.exe` en Windows). El updater busca ese patrón. `GOOS`/`GOARCH` se usan literalmente para que el mapeo sea directo.
|
||||
|
||||
### D6: Pipeline de release
|
||||
|
||||
- **Elección**: workflow en `.gitea/workflows/release.yml` con `on: push: tags: ['v*']`, runner `ubuntu-latest`, setup de Go 1.22 (action `actions/setup-go@v5`, compatible con Gitea Actions), bucle de build sobre las 3 plataformas con `CGO_ENABLED=0` y `ldflags` inyectando `main.Version` (desde `github.ref_name`), `main.GiteaURL`, `main.RepoOwner`, `main.RepoName` (desde `github.server_url` y el contexto del repo). Publicación con la acción `akkuman/gitea-release-action` o el CLI `tea release create` como fallback.
|
||||
- **Alternativa**: generar los binarios en Docker dentro del pipeline. Se descarta: el runner de Gitea ya provee el toolchain vía setup-go y es más rápido.
|
||||
|
||||
### D7: Devcontainer
|
||||
|
||||
- **Elección**: imagen `mcr.microsoft.com/devcontainers/go:1-1.22-bookworm` con:
|
||||
- Features: `ghcr.io/devcontainers/features/golang:1` no es necesaria (la imagen ya incluye Go); se añade la feature `docker-in-docker` opcional no requerida — se omite para minimizar superficie.
|
||||
- `postCreateCommand`: instalación de `golangci-lint` vía script oficial y `go mod download` si existe `go.mod`.
|
||||
- Extensiones: `golang.go` (Go oficial, incluye gopls), `eamodio.gitlens`.
|
||||
- `go.useLanguageServer: true` en settings del editor.
|
||||
- **Alternativa**: devcontainer con Dockerfile propio. Se descarta: la imagen oficial ya cubre todo el stack necesario.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [Contrato de nombres de assets roto si alguien renombra manualmente en Gitea] → El updater devuelve error claro "asset no encontrado para <GOOS>/<GOARCH>"; convención documentada en el workflow.
|
||||
- [Comparación semver casera falla con tags no numéricos (ej. `v1.0.0-rc1`)] → Si el parseo falla, se informa y no se actualiza (fail-safe); los tags del pipeline seguirán `vX.Y.Z`.
|
||||
- [`selfupdate.Apply` no funciona en algunos entornos (ej. binario en ruta sin permiso de escritura, Windows con AV bloqueando el reemplazo)] → `Apply` reemplaza atómicamente y respalda en `.old`; se devuelve el error al usuario sin dejar el binario corrupto.
|
||||
- [API key de Outline expuesta en el entorno del proceso] → Es el patrón estándar para servidores MCP stdio; no se loguea nunca la API key.
|
||||
- [Rate limits o cambios de la API de Outline] → Los endpoints usados (`collections.list`, `documents.search`, `documents.info`, `documents.create`) son estables; los errores HTTP se propagan con el mensaje de la API para diagnosticar rápido.
|
||||
- [Gitea Actions sin runners disponibles] → El release fallará visiblemente en el push del tag; el binario se puede compilar manualmente con los mismos comandos documentados en el workflow.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
No aplica (proyecto nuevo). Rollback: los releases de Gitea conservan los binarios anteriores; para revertir una actualización basta reinstalar el asset de la versión previa (el updater respalda el binario anterior en `<binary>.old`).
|
||||
|
||||
## Open Questions
|
||||
|
||||
- URL exacta de la instancia de Gitea y `owner/repo` definitivos: se inyectan en tiempo de build; se usarán placeholders en el workflow derivados del contexto del repositorio.
|
||||
- ¿Publicar también una imagen de contenedor del binario en el registry de Gitea? Fuera de alcance para este change; candidato para un change futuro.
|
||||
@@ -0,0 +1,45 @@
|
||||
# Proposal: create-outline-mcp-server
|
||||
|
||||
## Why
|
||||
|
||||
El equipo necesita que los asistentes de IA (clientes MCP) puedan consultar y crear contenido en nuestra instancia self-hosted de Outline de forma segura y estructurada. Actualmente no existe ningún servidor MCP para Outline en el ecosistema interno, por lo que es necesario construirlo desde cero en Go, con un entorno de desarrollo reproducible en contenedores y una cadena de distribución (releases binarios) basada en Gitea Actions.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Creación de un proyecto Go nuevo (`outline-mcp`) que implementa un servidor MCP con transporte stdio.
|
||||
- CLI básica con comandos `version` y `update`; sin argumentos arranca el servidor MCP.
|
||||
- Cliente HTTP (`OutlineClient`) para la API de Outline, autenticado mediante `OUTLINE_URL` y `OUTLINE_API_KEY`.
|
||||
- Cuatro herramientas MCP: `outline_list_collections`, `outline_search`, `outline_get_document` y `outline_create_document`.
|
||||
- Mecanismo de auto-actualización que consulta la última release de Gitea y aplica el binario correspondiente al SO/arquitectura actual.
|
||||
- Entorno de desarrollo en contenedor (`.devcontainer/devcontainer.json`) con imagen oficial de Go 1.22, gopls y golangci-lint.
|
||||
- Pipeline de CI/CD en Gitea Actions (`.gitea/workflows/release.yml`) que compila binarios estáticos para linux/amd64, darwin/arm64 y windows/amd64 y publica releases al pushear tags `v*`.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `mcp-server`: Servidor MCP en Go con transporte stdio, CLI básica (`version`, `update`) e inyección de metadatos de build mediante `-ldflags`.
|
||||
- `outline-api-client`: Cliente HTTP para la API de Outline con autenticación Bearer y las cuatro herramientas MCP sobre colecciones y documentos.
|
||||
- `self-update`: Actualización automática del binario comparando la versión actual con el último tag de release en Gitea y aplicando el asset compatible con `GOOS`/`GOARCH`.
|
||||
- `release-pipeline`: Pipeline de Gitea Actions que compila binarios estáticos multi-plataforma y publica releases en Gitea.
|
||||
- `dev-environment`: Entorno de desarrollo en contenedor (devcontainer) con tooling de Go preconfigurado.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
(ninguna — el proyecto se crea desde cero)
|
||||
|
||||
## No objetivos
|
||||
|
||||
- No se implementará transporte HTTP/SSE para el servidor MCP; solo stdio.
|
||||
- No se gestionarán operaciones avanzadas de Outline (eliminar/actualizar documentos, gestionar permisos, comentarios, attachments).
|
||||
- No se implementará autenticación OAuth del servidor MCP hacia los clientes; la seguridad se apoya en la API key de Outline vía entorno.
|
||||
- No se configurará firma de binarios ni notarización (macOS/Windows).
|
||||
- No se incluirá despliegue continuo ni instalación automática en servidores; solo publicación de releases.
|
||||
- No se desarrollará test suite de integración contra una instancia real de Outline.
|
||||
|
||||
## Impact
|
||||
|
||||
- **Código**: archivos nuevos en la raíz del repo (`main.go`, `go.mod`, `go.sum`, `.devcontainer/devcontainer.json`, `.gitea/workflows/release.yml`).
|
||||
- **Dependencias Go**: `github.com/mark3labs/mcp-go` (SDK MCP), `github.com/minio/selfupdate` (auto-update).
|
||||
- **APIs externas**: API REST de Outline (`/api/collections.list`, `/api/documents.search`, `/api/documents.info`, `/api/documents.create`) y API de releases de Gitea (`/api/v1/repos/{owner}/{repo}/releases/latest`).
|
||||
- **Infraestructura**: requiere Gitea con Actions habilitadas y un repositorio con registro de releases; el desarrollo no requiere Go local (contenedor).
|
||||
@@ -0,0 +1,17 @@
|
||||
# Spec: dev-environment
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Contenedor de desarrollo con Go 1.22
|
||||
El sistema SHALL incluir un devcontainer basado en la imagen oficial `mcr.microsoft.com/devcontainers/go:1-1.22-bookworm` que permita desarrollar el proyecto sin Go instalado localmente.
|
||||
|
||||
#### Scenario: Apertura del proyecto en el contenedor
|
||||
- **WHEN** el usuario abre el proyecto en DevPod o Dev Containers
|
||||
- **THEN** el contenedor se construye a partir de la imagen oficial de Go 1.22 y dispone del toolchain necesario para compilar y ejecutar el proyecto
|
||||
|
||||
### Requirement: Tooling del editor preconfigurado
|
||||
El devcontainer SHALL preconfigurar el soporte de `gopls` (language server de Go) e instalar `golangci-lint`, además de las extensiones básicas de Go para el editor.
|
||||
|
||||
#### Scenario: Experiencia de edición en el contenedor
|
||||
- **WHEN** el desarrollador edita archivos Go dentro del devcontainer
|
||||
- **THEN** dispone de autocompletado y diagnóstico vía gopls, de linting vía golangci-lint y de las extensiones de Go instaladas automáticamente
|
||||
@@ -0,0 +1,38 @@
|
||||
# Spec: mcp-server
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Arranque del servidor por defecto
|
||||
Cuando el binario se ejecuta sin argumentos, el sistema SHALL iniciar el servidor MCP usando transporte stdio.
|
||||
|
||||
#### Scenario: Ejecución sin argumentos
|
||||
- **WHEN** el usuario ejecuta el binario sin ningún argumento
|
||||
- **THEN** el sistema arranca el servidor MCP en modo stdio y queda a la espera de mensajes del cliente
|
||||
|
||||
### Requirement: Comando version
|
||||
El sistema SHALL exponer el comando `version` que imprime la versión del binario.
|
||||
|
||||
#### Scenario: Consulta de versión
|
||||
- **WHEN** el usuario ejecuta el binario con el argumento `version`
|
||||
- **THEN** el sistema imprime por stdout la versión inyectada en tiempo de compilación mediante `-ldflags`
|
||||
|
||||
### Requirement: Comando update
|
||||
El sistema SHALL exponer el comando `update` que ejecuta el proceso de auto-actualización del binario.
|
||||
|
||||
#### Scenario: Ejecución de actualización
|
||||
- **WHEN** el usuario ejecuta el binario con el argumento `update`
|
||||
- **THEN** el sistema consulta la última release de Gitea y aplica la actualización si existe una versión superior
|
||||
|
||||
### Requirement: Metadatos de build inyectados
|
||||
El sistema SHALL definir variables globales (`Version`, `GiteaURL`, `RepoOwner`, `RepoName`) que MUST ser inyectables en tiempo de compilación mediante `-ldflags -X`.
|
||||
|
||||
#### Scenario: Compilación con ldflags
|
||||
- **WHEN** el binario se compila pasando valores para `main.Version`, `main.GiteaURL`, `main.RepoOwner` y `main.RepoName` vía `-ldflags`
|
||||
- **THEN** el comando `version` y la lógica de auto-update utilizan esos valores en tiempo de ejecución
|
||||
|
||||
### Requirement: Registro de herramientas MCP
|
||||
El servidor MCP SHALL registrar las herramientas `outline_list_collections`, `outline_search`, `outline_get_document` y `outline_create_document` y MUST exponerlas vía el protocolo MCP.
|
||||
|
||||
#### Scenario: Listado de herramientas desde un cliente MCP
|
||||
- **WHEN** un cliente MCP solicita la lista de herramientas disponibles
|
||||
- **THEN** el servidor responde incluyendo las cuatro herramientas de Outline con sus esquemas de entrada definidos
|
||||
@@ -0,0 +1,61 @@
|
||||
# Spec: outline-api-client
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Configuración por variables de entorno
|
||||
El sistema SHALL configurar el cliente de Outline a partir de las variables de entorno `OUTLINE_URL` (URL base de la instancia) y `OUTLINE_API_KEY` (token de API).
|
||||
|
||||
#### Scenario: Cliente configurado correctamente
|
||||
- **WHEN** las variables `OUTLINE_URL` y `OUTLINE_API_KEY` están definidas en el entorno
|
||||
- **THEN** el cliente construye las peticiones contra la URL base indicada y autentica con el token provisto
|
||||
|
||||
#### Scenario: Variables de entorno ausentes
|
||||
- **WHEN** `OUTLINE_URL` o `OUTLINE_API_KEY` no están definidas al invocar una herramienta
|
||||
- **THEN** el sistema responde con un mensaje de error descriptivo indicando la configuración faltante
|
||||
|
||||
### Requirement: Petición POST genérica autenticada
|
||||
El cliente HTTP SHALL implementar un método genérico para realizar peticiones POST a los endpoints de la API de Outline, incluyendo el header `Authorization: Bearer <TOKEN>` y el body en formato JSON.
|
||||
|
||||
#### Scenario: Petición autenticada
|
||||
- **WHEN** el cliente envía una petición a cualquier endpoint de la API de Outline
|
||||
- **THEN** la petición incluye el header `Authorization: Bearer` con el token configurado y el payload serializado como JSON
|
||||
|
||||
#### Scenario: Error de la API de Outline
|
||||
- **WHEN** la API de Outline responde con un código HTTP de error
|
||||
- **THEN** el sistema propaga un error descriptivo (incluyendo el código y el mensaje de la API) hacia el llamador
|
||||
|
||||
### Requirement: Herramienta outline_list_collections
|
||||
La herramienta `outline_list_collections` SHALL invocar el endpoint `/api/collections.list` y devolver el ID, el nombre y la descripción de cada colección.
|
||||
|
||||
#### Scenario: Listado de colecciones exitoso
|
||||
- **WHEN** se invoca `outline_list_collections` sin parámetros
|
||||
- **THEN** la herramienta devuelve la lista de colecciones con sus campos `id`, `name` y `description`
|
||||
|
||||
### Requirement: Herramienta outline_search
|
||||
La herramienta `outline_search` SHALL invocar el endpoint `/api/documents.search` recibiendo el parámetro `query` y devolver los resultados de la búsqueda.
|
||||
|
||||
#### Scenario: Búsqueda con resultados
|
||||
- **WHEN** se invoca `outline_search` con un `query` válido
|
||||
- **THEN** la herramienta devuelve los documentos coincidentes con su información relevante (título, id y extracto)
|
||||
|
||||
#### Scenario: Búsqueda sin resultados
|
||||
- **WHEN** se invoca `outline_search` con un `query` que no coincide con ningún documento
|
||||
- **THEN** la herramienta devuelve una lista vacía sin error
|
||||
|
||||
### Requirement: Herramienta outline_get_document
|
||||
La herramienta `outline_get_document` SHALL invocar el endpoint `/api/documents.info` recibiendo el parámetro `id` y devolver el título y el texto del documento en formato Markdown.
|
||||
|
||||
#### Scenario: Lectura de documento existente
|
||||
- **WHEN** se invoca `outline_get_document` con el `id` de un documento existente
|
||||
- **THEN** la herramienta devuelve el título del documento y su contenido en Markdown
|
||||
|
||||
#### Scenario: Documento inexistente
|
||||
- **WHEN** se invoca `outline_get_document` con un `id` que no corresponde a ningún documento
|
||||
- **THEN** la herramienta devuelve un error indicando que el documento no fue encontrado
|
||||
|
||||
### Requirement: Herramienta outline_create_document
|
||||
La herramienta `outline_create_document` SHALL invocar el endpoint `/api/documents.create` recibiendo los parámetros `title`, `text` (Markdown) y `collection_id`, y devolver la información del documento creado.
|
||||
|
||||
#### Scenario: Creación de documento exitosa
|
||||
- **WHEN** se invoca `outline_create_document` con `title`, `text` y un `collection_id` válido
|
||||
- **THEN** la herramienta crea el documento en la colección indicada y devuelve su `id` y `title`
|
||||
@@ -0,0 +1,42 @@
|
||||
# Spec: release-pipeline
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Disparo por tags de versión
|
||||
El pipeline de release SHALL ejecutarse cuando se realice push de tags cuyo nombre comience con `v` (por ejemplo `v1.0.0`).
|
||||
|
||||
#### Scenario: Push de tag de release
|
||||
- **WHEN** se pushea al repositorio un tag que empieza con `v`
|
||||
- **THEN** el workflow de Gitea Actions se dispara automáticamente
|
||||
|
||||
#### Scenario: Push sin tag de release
|
||||
- **WHEN** se pushea una rama sin tags o un tag que no empieza con `v`
|
||||
- **THEN** el workflow de release no se ejecuta
|
||||
|
||||
### Requirement: Entorno de compilación
|
||||
El pipeline SHALL utilizar una imagen de Ubuntu y SHALL configurar Go 1.22 como versión del toolchain antes de compilar.
|
||||
|
||||
#### Scenario: Job de build
|
||||
- **WHEN** el pipeline se ejecuta
|
||||
- **THEN** el entorno de build dispone de Go 1.22 instalado sobre una imagen Ubuntu
|
||||
|
||||
### Requirement: Inyección de variables en la compilación
|
||||
El pipeline SHALL inyectar en tiempo de compilación las variables `Version`, `GiteaURL`, `RepoOwner` y `RepoName` mediante `-ldflags`, derivadas del tag y del repositorio.
|
||||
|
||||
#### Scenario: Compilación con metadatos
|
||||
- **WHEN** el pipeline compila los binarios
|
||||
- **THEN** los binarios resultantes contienen la versión del tag y los datos del repositorio Gitea para el mecanismo de auto-update
|
||||
|
||||
### Requirement: Compilación multi-plataforma estática
|
||||
El pipeline SHALL compilar binarios estáticos (`CGO_ENABLED=0`) para las plataformas linux/amd64, darwin/arm64 y windows/amd64.
|
||||
|
||||
#### Scenario: Artefactos generados
|
||||
- **WHEN** el job de build completa la compilación
|
||||
- **THEN** se generan tres binarios estáticos: uno para linux amd64, uno para darwin arm64 (Apple Silicon) y uno para windows amd64
|
||||
|
||||
### Requirement: Publicación del release en Gitea
|
||||
El pipeline SHALL publicar un release en Gitea asociado al tag, adjuntando los binarios compilados como assets, utilizando la acción oficial de Gitea o un CLI compatible.
|
||||
|
||||
#### Scenario: Release publicado
|
||||
- **WHEN** la compilación multi-plataforma finaliza con éxito
|
||||
- **THEN** se crea (o actualiza) el release del tag en Gitea con los tres binarios adjuntos
|
||||
@@ -0,0 +1,47 @@
|
||||
# Spec: self-update
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Consulta de la última release de Gitea
|
||||
El sistema SHALL consultar el endpoint `/api/v1/repos/{owner}/{repo}/releases/latest` de la instancia de Gitea configurada para obtener la última release disponible.
|
||||
|
||||
#### Scenario: Consulta exitosa de última release
|
||||
- **WHEN** se ejecuta la lógica de auto-actualización y la API de Gitea responde correctamente
|
||||
- **THEN** el sistema obtiene el tag de la release y la lista de assets publicados
|
||||
|
||||
#### Scenario: Gitea no accesible
|
||||
- **WHEN** la instancia de Gitea no es accesible o responde con error
|
||||
- **THEN** el sistema finaliza con un mensaje de error sin modificar el binario actual
|
||||
|
||||
### Requirement: Comparación de versiones
|
||||
El sistema SHALL comparar la versión actual del binario (`Version` inyectada vía ldflags) con el tag de la última release de Gitea, y MUST omitir la actualización si la versión actual es igual o superior.
|
||||
|
||||
#### Scenario: Versión actualizada disponible
|
||||
- **WHEN** el tag de Gitea indica una versión superior a la versión actual
|
||||
- **THEN** el sistema procede a descargar el asset correspondiente
|
||||
|
||||
#### Scenario: Versión ya actualizada
|
||||
- **WHEN** la versión actual es igual o superior al tag de la última release
|
||||
- **THEN** el sistema informa que no hay actualizaciones y no realiza cambios en el binario
|
||||
|
||||
### Requirement: Descarga del asset compatible
|
||||
El sistema SHALL seleccionar el asset de la release cuyo nombre corresponda al sistema operativo y arquitectura actuales (`runtime.GOOS`, `runtime.GOARCH`), y MUST descargarlo antes de aplicar la actualización.
|
||||
|
||||
#### Scenario: Asset compatible disponible
|
||||
- **WHEN** la release contiene un asset que coincide con el `GOOS`/`GOARCH` actuales
|
||||
- **THEN** el sistema descarga dicho asset para aplicar la actualización
|
||||
|
||||
#### Scenario: Asset compatible no disponible
|
||||
- **WHEN** la release no contiene un asset para la plataforma actual
|
||||
- **THEN** el sistema finaliza con un error indicando que no existe binario para la plataforma
|
||||
|
||||
### Requirement: Aplicación del binario descargado
|
||||
El sistema SHALL aplicar el binario descargado utilizando `selfupdate.Apply` (github.com/minio/selfupdate), reemplazando el binario en ejecución.
|
||||
|
||||
#### Scenario: Actualización aplicada correctamente
|
||||
- **WHEN** el asset descargado es un binario válido
|
||||
- **THEN** el sistema reemplaza el binario actual mediante `selfupdate.Apply` e informa el éxito de la operación
|
||||
|
||||
#### Scenario: Asset corrupto o inválido
|
||||
- **WHEN** el asset descargado no es un binario válido
|
||||
- **THEN** el sistema aborta la actualización e informa el error sin dejar el binario en estado inconsistente
|
||||
@@ -0,0 +1,53 @@
|
||||
# Tasks: create-outline-mcp-server
|
||||
|
||||
## 1. Entorno de desarrollo (devcontainer)
|
||||
|
||||
- [x] 1.1 Crear `.devcontainer/devcontainer.json` con la imagen `mcr.microsoft.com/devcontainers/go:1-1.22-bookworm`
|
||||
- [x] 1.2 Configurar extensiones del editor (`golang.go` con gopls) y settings (`go.useLanguageServer: true`)
|
||||
- [x] 1.3 Añadir `postCreateCommand` que instale `golangci-lint` y ejecute `go mod download` cuando exista `go.mod`
|
||||
- [x] 1.4 Verificar: Given el proyecto abierto en DevPod/Dev Containers, When el contenedor se construye, Then dispone de Go 1.22, gopls y golangci-lint operativos
|
||||
|
||||
## 2. Inicialización del módulo Go
|
||||
|
||||
- [ ] 2.1 Ejecutar `go mod init outline-mcp` dentro del contenedor
|
||||
- [ ] 2.2 Instalar dependencias: `go get github.com/mark3labs/mcp-go/mcp github.com/mark3labs/mcp-go/server`
|
||||
- [ ] 2.3 Instalar la librería de auto-update: `go get github.com/minio/selfupdate`
|
||||
- [ ] 2.4 Verificar: Given `go.mod` creado, When se ejecuta `go mod tidy`, Then no hay errores y `go.sum` queda generado
|
||||
|
||||
## 3. CLI y esqueleto del servidor MCP
|
||||
|
||||
- [ ] 3.1 Crear `main.go` con variables globales inyectables (`Version`, `GiteaURL`, `RepoOwner`, `RepoName`) y parsing de argumentos (`version`, `update`; sin argumentos → servidor MCP)
|
||||
- [ ] 3.2 Implementar el comando `version` que imprime la versión compilada
|
||||
- [ ] 3.3 Arrancar el servidor MCP con `server.NewMCPServer` y transporte stdio (`ServeStdio`)
|
||||
- [ ] 3.4 Verificar: Given el binario compilado con `-ldflags -X main.Version=v0.0.1-dev`, When se ejecuta `version`, Then imprime `v0.0.1-dev`; When se ejecuta sin argumentos, Then el proceso queda a la espera en stdio
|
||||
|
||||
## 4. Cliente HTTP de Outline
|
||||
|
||||
- [ ] 4.1 Implementar el struct `OutlineClient` configurado desde `OUTLINE_URL` y `OUTLINE_API_KEY`
|
||||
- [ ] 4.2 Implementar método genérico `post(ctx, path, payload, result)` que serialice JSON, incluya el header `Authorization: Bearer <TOKEN>` y propague errores HTTP con el mensaje de la API
|
||||
- [ ] 4.3 Verificar: Given `OUTLINE_URL`/`OUTLINE_API_KEY` ausentes, When se invoca una herramienta, Then se responde con error descriptivo sin panic
|
||||
|
||||
## 5. Herramientas MCP
|
||||
|
||||
- [ ] 5.1 Implementar `outline_list_collections` contra `/api/collections.list` devolviendo `id`, `name` y `description`
|
||||
- [ ] 5.2 Implementar `outline_search` contra `/api/documents.search` con parámetro `query`
|
||||
- [ ] 5.3 Implementar `outline_get_document` contra `/api/documents.info` con parámetro `id`, devolviendo título y texto en Markdown
|
||||
- [ ] 5.4 Implementar `outline_create_document` contra `/api/documents.create` con parámetros `title`, `text` y `collection_id`
|
||||
- [ ] 5.5 Registrar las cuatro herramientas en el servidor MCP con sus esquemas de entrada (`mcp.WithString`, `mcp.Required()`)
|
||||
- [ ] 5.6 Verificar: Given un cliente MCP conectado por stdio, When se lista `tools/list`, Then aparecen las cuatro herramientas con sus esquemas; When se invoca `outline_search` con query sin coincidencias, Then devuelve lista vacía sin error
|
||||
|
||||
## 6. Auto-update
|
||||
|
||||
- [ ] 6.1 Implementar `doUpdate`: consulta a `{GiteaURL}/api/v1/repos/{RepoOwner}/{RepoName}/releases/latest` y manejo de errores de red
|
||||
- [ ] 6.2 Implementar comparación de versiones (parseo de `vX.Y.Z` frente a `Version`; fail-safe si el tag no es parseable)
|
||||
- [ ] 6.3 Implementar selección y descarga del asset por convención `outline-mcp_{GOOS}_{GOARCH}[.exe]` usando `runtime.GOOS`/`runtime.GOARCH`
|
||||
- [ ] 6.4 Aplicar el binario descargado con `selfupdate.Apply` e informar el resultado
|
||||
- [ ] 6.5 Verificar: Given `Version` igual o superior al tag de Gitea, When se ejecuta `update`, Then informa que no hay actualizaciones y no modifica el binario; Given la API de Gitea inaccesible, Then finaliza con error sin tocar el binario
|
||||
|
||||
## 7. Pipeline de release (Gitea Actions)
|
||||
|
||||
- [ ] 7.1 Crear `.gitea/workflows/release.yml` con trigger `on: push: tags: ['v*']` y runner `ubuntu-latest`
|
||||
- [ ] 7.2 Configurar Go 1.22 en el job (`actions/setup-go@v5`)
|
||||
- [ ] 7.3 Implementar el build con `CGO_ENABLED=0` para linux/amd64, darwin/arm64 y windows/amd64, nombrando los artefactos `outline-mcp_{GOOS}_{GOARCH}[.exe]` e inyectando `-ldflags` con `Version` (desde `github.ref_name`), `GiteaURL`, `RepoOwner` y `RepoName` (desde el contexto del repo)
|
||||
- [ ] 7.4 Publicar el release en Gitea adjuntando los tres binarios (acción oficial de Gitea o CLI `tea release create`)
|
||||
- [ ] 7.5 Verificar: Given un push de tag `v0.1.0`, When el workflow se ejecuta, Then el release queda publicado en Gitea con los tres assets y el comando `version` del binario publicado reporta `v0.1.0`
|
||||
@@ -0,0 +1,31 @@
|
||||
schema: spec-driven
|
||||
|
||||
# Project context (optional)
|
||||
# This is shown to AI when creating artifacts.
|
||||
# Add your tech stack, conventions, style guides, domain knowledge, etc.
|
||||
# Example:
|
||||
# context: |
|
||||
# Tech stack: TypeScript, React, Node.js
|
||||
# We use conventional commits
|
||||
# Domain: e-commerce platform
|
||||
|
||||
# Per-artifact rules (optional)
|
||||
# Add custom rules for specific artifacts.
|
||||
# Example:
|
||||
# rules:
|
||||
# proposal:
|
||||
# - Keep proposals under 500 words
|
||||
# - Always include a "Non-goals" section
|
||||
# tasks:
|
||||
# - Break tasks into chunks of max 2 hours
|
||||
context: |
|
||||
Idioma: Español.
|
||||
Todos los artefactos deben escribirse en español.
|
||||
Mantener los terminos tecnicos en inglés cuando corresponda (por ejemplo: API, frontend, backend, database).
|
||||
Usar un tono formal y profesional.
|
||||
|
||||
rules:
|
||||
proposal:
|
||||
- Incluir siempre una sección de "No objetivos" para aclarar lo que no se abordará.
|
||||
tasks:
|
||||
- Use Given/When/Then format
|
||||
Reference in New Issue
Block a user