configuracion de entorno de desarrollo
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user