# 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