Skip to main content
Glama
AlexHerranr

MCP Spreadsheets

by AlexHerranr
README.md
# MCP Spreadsheets

Servidor MCP (Model Context Protocol) para control total de Google Sheets desde Claude Code.

## Descripción

Este MCP permite manipular spreadsheets de Google directamente desde Claude Code sin necesidad de escribir scripts. Cada operación se ejecuta en segundos mediante comandos directos.

```
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   Claude Code   │────▶│  MCP Server     │────▶│  Google Sheets  │
│   (tu prompt)   │     │  (siempre on)   │     │  API v4         │
└─────────────────┘     └─────────────────┘     └─────────────────┘
```

## Instalación

### 1. Instalar dependencias

```bash
cd mcp-spreadsheets
npm install
npm run build
```

### 2. Configurar credenciales

Copia tu archivo de credenciales de Google Service Account a la carpeta:

```bash
cp /ruta/a/tu/service-account.json ./credentials.json
```

O configura variables de entorno:

```bash
export GOOGLE_SERVICE_ACCOUNT_PATH=/ruta/a/credentials.json
```

### 3. Registrar en Claude Code

Agrega a tu archivo de configuración de Claude Code (`~/.claude.json` o `settings.json`):

```json
{
  "mcpServers": {
    "spreadsheets": {
      "command": "node",
      "args": ["/ruta/completa/a/mcp-spreadsheets/dist/index.js"],
      "env": {
        "GOOGLE_SERVICE_ACCOUNT_PATH": "/ruta/a/credentials.json"
      }
    }
  }
}
```

## Categorías y Tools

### Datos

Operaciones de lectura y escritura de datos.

| Tool | Descripción | Parámetros |
|------|-------------|------------|
| `sheets_read_range` | Lee datos de un rango | `spreadsheetId`, `sheetName`, `range` |
| `sheets_write_range` | Escribe datos en un rango | `spreadsheetId`, `sheetName`, `range`, `values` |
| `sheets_append_rows` | Agrega filas al final | `spreadsheetId`, `sheetName`, `rows` |
| `sheets_delete_rows` | Elimina filas | `spreadsheetId`, `sheetName`, `startIndex`, `count` |
| `sheets_get_rows` | Obtiene filas como objetos | `spreadsheetId`, `sheetName`, `limit?` |

**Ejemplos:**

```
// Leer datos
sheets_read_range(spreadsheetId: "abc123", sheetName: "Ventas", range: "A1:D10")

// Escribir datos
sheets_write_range(spreadsheetId: "abc123", sheetName: "Ventas", range: "A1", values: [["Nombre", "Precio"], ["Producto 1", 100]])

// Agregar filas
sheets_append_rows(spreadsheetId: "abc123", sheetName: "Ventas", rows: [{Nombre: "Producto 2", Precio: 200}])
```

---

### Formato

Aplicar estilos visuales a celdas.

| Tool | Descripción | Parámetros |
|------|-------------|------------|
| `sheets_format_range` | Aplica formato a celdas | `spreadsheetId`, `sheetName`, `range`, `backgroundColor?`, `textColor?`, `bold?`, `italic?`, `fontSize?`, `horizontalAlignment?` |
| `sheets_clear_format` | Limpia todo el formato | `spreadsheetId`, `sheetName`, `range` |

**Ejemplos:**

```
// Poner fondo verde y texto blanco en negrita
sheets_format_range(
  spreadsheetId: "abc123",
  sheetName: "Ventas",
  range: "A1:D1",
  backgroundColor: "#00ff00",
  textColor: "#ffffff",
  bold: true
)

// Limpiar formato
sheets_clear_format(spreadsheetId: "abc123", sheetName: "Ventas", range: "A2:D100")
```

---

### Formato Condicional

Reglas automáticas que cambian el formato según condiciones.

| Tool | Descripción | Parámetros |
|------|-------------|------------|
| `sheets_get_conditional_rules` | Lista todas las reglas | `spreadsheetId`, `sheetName` |
| `sheets_add_conditional_rule` | Agrega una regla | `spreadsheetId`, `sheetName`, `formula`, `backgroundColor?`, `textColor?`, `bold?`, `priority?` |
| `sheets_delete_conditional_rule` | Elimina una regla por índice | `spreadsheetId`, `sheetName`, `index` |
| `sheets_clear_conditional_rules` | Elimina TODAS las reglas | `spreadsheetId`, `sheetName` |

**Ejemplos:**

```
// Ver reglas existentes
sheets_get_conditional_rules(spreadsheetId: "abc123", sheetName: "Reservas")

// Agregar regla: si Canal = "airbnb", fondo verde
sheets_add_conditional_rule(
  spreadsheetId: "abc123",
  sheetName: "Reservas",
  formula: '=LOWER($J2)="airbnb"',
  backgroundColor: "#ccffcc",
  priority: 0
)

// Agregar regla: si Total = 0, fondo amarillo
sheets_add_conditional_rule(
  spreadsheetId: "abc123",
  sheetName: "Reservas",
  formula: '=AND(LEN($A2)>0,$V2=0)',
  backgroundColor: "#ffffcc",
  priority: 1
)

// Eliminar regla índice 0
sheets_delete_conditional_rule(spreadsheetId: "abc123", sheetName: "Reservas", index: 0)

// Limpiar todas las reglas
sheets_clear_conditional_rules(spreadsheetId: "abc123", sheetName: "Reservas")
```

---

### Hojas

Gestión de hojas dentro del spreadsheet.

| Tool | Descripción | Parámetros |
|------|-------------|------------|
| `sheets_list_sheets` | Lista todas las hojas | `spreadsheetId` |
| `sheets_create_sheet` | Crea nueva hoja | `spreadsheetId`, `title`, `headers?` |
| `sheets_delete_sheet` | Elimina una hoja | `spreadsheetId`, `sheetName` |
| `sheets_rename_sheet` | Renombra una hoja | `spreadsheetId`, `oldName`, `newName` |
| `sheets_duplicate_sheet` | Duplica una hoja | `spreadsheetId`, `sheetName`, `newName` |
| `sheets_hide_sheet` | Oculta/muestra hoja | `spreadsheetId`, `sheetName`, `hidden` |

**Ejemplos:**

```
// Ver todas las hojas
sheets_list_sheets(spreadsheetId: "abc123")

// Crear hoja con headers
sheets_create_sheet(
  spreadsheetId: "abc123",
  title: "Reporte Mensual",
  headers: ["Fecha", "Ventas", "Gastos", "Ganancia"]
)

// Duplicar hoja
sheets_duplicate_sheet(spreadsheetId: "abc123", sheetName: "Plantilla", newName: "Enero 2024")

// Ocultar hoja
sheets_hide_sheet(spreadsheetId: "abc123", sheetName: "Datos Internos", hidden: true)
```

---

### Celdas

Operaciones sobre celdas individuales o rangos.

| Tool | Descripción | Parámetros |
|------|-------------|------------|
| `sheets_merge_cells` | Combina celdas | `spreadsheetId`, `sheetName`, `range` |
| `sheets_unmerge_cells` | Separa celdas combinadas | `spreadsheetId`, `sheetName`, `range` |
| `sheets_freeze_rows` | Congela filas superiores | `spreadsheetId`, `sheetName`, `count` |
| `sheets_freeze_columns` | Congela columnas izquierdas | `spreadsheetId`, `sheetName`, `count` |
| `sheets_set_column_width` | Ajusta ancho de columna | `spreadsheetId`, `sheetName`, `column`, `width` |
| `sheets_set_row_height` | Ajusta altura de fila | `spreadsheetId`, `sheetName`, `row`, `height` |

**Ejemplos:**

```
// Combinar celdas para título
sheets_merge_cells(spreadsheetId: "abc123", sheetName: "Reporte", range: "A1:D1")

// Congelar primera fila (headers)
sheets_freeze_rows(spreadsheetId: "abc123", sheetName: "Datos", count: 1)

// Ajustar ancho de columna A a 200px
sheets_set_column_width(spreadsheetId: "abc123", sheetName: "Datos", column: "A", width: 200)
```

---

### Validación

Restricciones y listas desplegables.

| Tool | Descripción | Parámetros |
|------|-------------|------------|
| `sheets_add_dropdown` | Agrega lista desplegable | `spreadsheetId`, `sheetName`, `range`, `options` |
| `sheets_remove_validation` | Elimina validación | `spreadsheetId`, `sheetName`, `range` |

**Ejemplos:**

```
// Agregar dropdown de estados
sheets_add_dropdown(
  spreadsheetId: "abc123",
  sheetName: "Tareas",
  range: "C2:C100",
  options: ["Pendiente", "En Progreso", "Completado", "Cancelado"]
)

// Quitar validación
sheets_remove_validation(spreadsheetId: "abc123", sheetName: "Tareas", range: "C2:C100")
```

---

### Filtros

Activar y desactivar filtros automáticos.

| Tool | Descripción | Parámetros |
|------|-------------|------------|
| `sheets_set_filter` | Activa filtro en rango | `spreadsheetId`, `sheetName`, `range` |
| `sheets_clear_filter` | Elimina filtro | `spreadsheetId`, `sheetName` |

**Ejemplos:**

```
// Activar filtro en tabla
sheets_set_filter(spreadsheetId: "abc123", sheetName: "Ventas", range: "A1:F100")

// Quitar filtro
sheets_clear_filter(spreadsheetId: "abc123", sheetName: "Ventas")
```

---

### Protección

Proteger rangos contra edición accidental.

| Tool | Descripción | Parámetros |
|------|-------------|------------|
| `sheets_protect_range` | Protege un rango | `spreadsheetId`, `sheetName`, `range`, `description` |

**Ejemplos:**

```
// Proteger fórmulas
sheets_protect_range(
  spreadsheetId: "abc123",
  sheetName: "Calculadora",
  range: "E1:E100",
  description: "Columna de fórmulas - No editar"
)
```

---

### Info

Información general del spreadsheet.

| Tool | Descripción | Parámetros |
|------|-------------|------------|
| `sheets_get_info` | Info del spreadsheet | `spreadsheetId` |

**Ejemplos:**

```
// Ver información
sheets_get_info(spreadsheetId: "abc123")
// Retorna: { title, locale, timeZone, sheets: [...] }
```

---

---

### Base de Datos (Reservas)

Consultas directas a PostgreSQL para obtener información de reservas.

| Tool | Descripción | Parámetros |
|------|-------------|------------|
| `db_get_reservas_futuras` | Reservas futuras de Pa'Cartagena | - |
| `db_get_tours_terceros` | Reservas de Tours y Terceros | - |
| `db_get_reserva_by_id` | Buscar reserva por ID | `bookingId` |
| `db_count_reservas` | Contar reservas (total, futuras, tours) | - |
| `db_get_reservas_por_fecha` | Reservas entre dos fechas | `desde`, `hasta` |
| `db_get_reservas_por_canal` | Reservas de un canal | `canal` |
| `db_get_estadisticas_canales` | Estadísticas por canal | - |

**Ejemplos:**

```
// ¿Hay tours esta semana?
db_get_tours_terceros()

// ¿Cuántas reservas de Airbnb hay?
db_get_reservas_por_canal(canal: "airbnb")

// Estadísticas generales
db_count_reservas()
// Retorna: { total: 2536, futuras: 107, tours: 1 }

// Reservas de febrero
db_get_reservas_por_fecha(desde: "2026-02-01", hasta: "2026-02-28")
```

**Nota:** Requiere configurar `DATABASE_URL` en el entorno.

---

## Resumen de Categorías

| Categoría | Tools | Descripción |
|-----------|-------|-------------|
| **Datos** | 5 | Leer, escribir, insertar, eliminar filas |
| **Formato** | 2 | Colores, fuentes, negrita, alineación |
| **Formato Condicional** | 4 | Reglas automáticas por fórmula |
| **Hojas** | 6 | Crear, eliminar, renombrar, duplicar, ocultar |
| **Celdas** | 6 | Merge, freeze, ancho/alto |
| **Validación** | 2 | Dropdowns, restricciones |
| **Filtros** | 2 | Activar/desactivar filtros |
| **Protección** | 1 | Proteger rangos |
| **Info** | 1 | Información del spreadsheet |
| **Base de Datos** | 7 | Consultar reservas de PostgreSQL |
| **TOTAL** | **36 tools** | |

---

## Flujo de Uso

### Antes (con scripts)
```
Usuario pide cambio
    → Desarrollador edita código
    → Compila
    → Ejecuta
    → Verifica resultado
    ≈ 2-5 minutos
```

### Ahora (con MCP)
```
Usuario pide cambio
    → Claude invoca tool
    → Resultado inmediato
    ≈ 2-5 segundos
```

---

## Notas Técnicas

- **Autenticación:** Service Account de Google (no requiere OAuth interactivo)
- **API:** Google Sheets API v4
- **Protocolo:** Model Context Protocol (MCP) sobre stdio
- **Caché:** Los documentos se cachean para evitar re-cargas innecesarias

## Requisitos

- Node.js 18+
- Service Account de Google Cloud con permisos de Sheets
- El spreadsheet debe estar compartido con el email del Service Account

## Licencia

MIT