Skip to main content
Glama
MCP Polygon Renderer

MCP Polygon Renderer

by bentlyy
README.md
# MCP Polygon Renderer

[![PyPI](https://img.shields.io/badge/pypi-mcp--polygon--renderer-blue)](https://pypi.org/project/mcp-polygon-renderer/)
[![Python](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
[![MCP](https://img.shields.io/badge/MCP-Compatible-purple.svg)](https://modelcontextprotocol.io)
[![Tests](https://github.com/bentlyy/mcp-polygon-renderer/actions/workflows/tests.yml/badge.svg)](https://github.com/bentlyy/mcp-polygon-renderer/actions/workflows/tests.yml)

> Servidor MCP que permite a agentes de IA poligonizar imágenes con OpenCV, usando grillas de referencia o coordenadas directas en píxeles.

## Por qué existe

Los modelos de lenguaje no pueden dibujar sobre imágenes. Esta herramienta les da esa capacidad: el agente razonifica sobre una imagen con grilla, define regiones usando celdas (ej: `"B3", "C3", "D3"`), y el servidor las renderiza con precisión de píxeles.

## Instalación

```bash
pip install mcp-polygon-renderer
```

O desde fuente:

```bash
git clone https://github.com/bentlyy/mcp-polygon-renderer.git
cd mcp-polygon-renderer
pip install -e .
```

## Configuración

El servidor **solo lee imágenes dentro de un directorio de trabajo** y escribe
los resultados en la subcarpeta `salida/` de ese mismo directorio. Define
`MCP_POLYGON_ROOT` apuntando a la carpeta donde tienes tus imágenes:

```bash
# Linux / macOS
export MCP_POLYGON_ROOT="/ruta/a/mis/imagenes"
```

```powershell
# Windows PowerShell
$env:MCP_POLYGON_ROOT = "C:\ruta\a\mis\imagenes"
```

Si no la defines, usa el directorio desde donde se lanza el servidor.

Después, registra el servidor en tu cliente MCP:

### Claude Desktop

```json
{
  "mcpServers": {
    "polygon-renderer": {
      "command": "python",
      "args": ["-m", "mcp_polygon_renderer"],
      "env": {
        "MCP_POLYGON_ROOT": "/ruta/a/mis/imagenes"
      }
    }
  }
}
```

### opencode

```json
{
  "mcp": {
    "polygon-renderer": {
      "command": "python",
      "args": ["-m", "mcp_polygon_renderer"],
      "environment": {
        "MCP_POLYGON_ROOT": "/ruta/a/mis/imagenes"
      }
    }
  }
}
```

## Herramientas

| Herramienta | Descripción |
|-------------|-------------|
| `preparar_imagen` | Superpone grilla etiquetada (A1, B2...) y devuelve el mapa de celdas en píxeles |
| `renderizar_desde_grid` | Renderiza polígonos a partir de celdas de grilla |
| `renderizar_poligonos` | Renderiza polígonos con coordenadas directas en píxeles |
| `detectar_regiones` | Detecta y colorea automáticamente regiones delimitadas por líneas |
| `ver_imagen` | Devuelve una imagen en base64 para que el agente la visualice |

## Seguridad

Un servidor MCP se ejecuta con tus permisos dentro de tu máquina, y sus
resultados se envían al modelo. Por eso el alcance está acotado a propósito:

| Control | Valor |
|---------|-------|
| Directorio permitido | `MCP_POLYGON_ROOT` (por defecto, el cwd) |
| Extensiones de entrada | `.png .jpg .jpeg .webp .bmp .tif .tiff` |
| Tamaño máximo de entrada | 25 MB |
| Lado máximo de la grilla | 64 celdas |
| Polígonos por llamada | 200 |
| Puntos por polígono | 5000 |

`ver_imagen` es la herramienta sensible: sin el confinamiento, un agente (o un
prompt injection en un archivo que procesa) podría leer `~/.ssh/id_rsa`, un
`.env` o cualquier otro archivo del disco y recibir su contenido en base64 como
respuesta. Por eso toda ruta se canonicaliza con `Path.resolve()` y se verifica
contra la raíz con `os.path.commonpath` antes de abrir nada.

Los límites de entrada no son cosméticos: `filas=2000` generaba 4.000.000 de
celdas y colgaba el proceso.

## Flujo de trabajo

### Modo grilla (recomendado para imágenes complejas)

```
1. Agente llama: preparar_imagen("vaca.png", filas=10, columnas=10)
   → Recibe: imagen con grilla + mapa de celdas en píxeles

2. Agente analiza la imagen con grilla y define regiones:
   {"poligonos_grid": [{"id": "Lomo", "celdas": ["F2", "G2", "G3", "H2"]}]}

3. Agente llama: renderizar_desde_grid("vaca.png", json_ia, mapa_celdas)
   → Recibe: ruta de la imagen con polígonos renderizados

4. Agente llama: ver_imagen(ruta_final)
   → Ve el resultado y continúa trabajando
```

### Modo directo (para formas geométricas)

```
1. Agente define polígonos con coordenadas en píxeles:
   [{"id": "Triangulo", "puntos": [[100,100], [200,50], [300,100]]}]

2. Agente llama: renderizar_poligonos("imagen.png", poligonos)
   → Recibe: ruta de la imagen con polígonos renderizados
```

### Detección automática

```
1. Agente llama: detectar_regiones("vaca.png")
   → Recibe: imagen coloreada + número de regiones detectadas
```

## Ejemplos

### Cortes de carne (35 regiones detectadas)

```python
# El agente analiza la vaca con grilla y define los cortes
poligonos = {
    "poligonos_grid": [
        {"id": "Cabeza", "celdas": ["A2", "A3", "B2", "B3"]},
        {"id": "Cuello", "celdas": ["B4", "C3", "C4"]},
        {"id": "Paleta", "celdas": ["B5", "C5", "D4", "D5"]},
        {"id": "Costilla", "celdas": ["D3", "E3", "E4", "F4", "F5"]},
        {"id": "Lomo", "celdas": ["F2", "G2", "G3", "H2", "H3"]},
        {"id": "Cuadril", "celdas": ["H4", "I3", "I4", "J3", "J4"]},
    ]
}
```

### Polígonos con curvas

```python
# Círculo con 36 puntos para simular curva suave
import math
puntos_circulo = [
    [int(200 + 80 * math.cos(2 * math.pi * i / 36)),
     int(150 + 80 * math.sin(2 * math.pi * i / 36))]
    for i in range(36)
]
poligonos = [{"id": "Circulo", "puntos": puntos_circulo}]
```

Los tres ejemplos ejecutables están en [`examples/`](examples/).

## Pruebas visuales

### 6 formas geométricas detectadas y coloreadas

![Formas originales](https://raw.githubusercontent.com/bentlyy/mcp-polygon-renderer/main/figuras.png)
![Formas coloreadas](https://raw.githubusercontent.com/bentlyy/mcp-polygon-renderer/main/salida/figuras_coloreadas.png)

### 16 regiones de mapa detectadas y coloreadas

![Mapa original](https://raw.githubusercontent.com/bentlyy/mcp-polygon-renderer/main/mapa.png)
![Mapa coloreado](https://raw.githubusercontent.com/bentlyy/mcp-polygon-renderer/main/salida/imagen_coloreada.png)

## Características

- **Optimizado para agentes**: sin ventanas emergentes, todo se guarda en disco
- **Confinado a un directorio**: no puede leer ni escribir fuera de `MCP_POLYGON_ROOT`
- **Eficiente en RAM**: carga reducida de imágenes grandes automáticamente
- **Colores vivos**: paleta de 40 colores distintos para diferenciar regiones
- **Curvas por densidad**: más puntos = más suavidad en bordes curvos
- **Detección automática**: identifica regiones delimitadas por líneas de color

## Desarrollo

```bash
pip install -e ".[dev]"
pytest tests/ -v
```

## Licencia

MIT — ver [LICENSE](LICENSE).

Las imágenes de ejemplo (`vaca.png`, `figuras.png`, `mapa.png`) son obra propia
del autor y se distribuyen bajo la misma licencia.

Proyecto no afiliado a Anthropic ni al proyecto OpenCV.