Skip to main content
Glama
mzoffoli85

MPC-PoC-2-ResourceProvider-GoogleSheets

by mzoffoli85

MPC-PoC-2-ResourceProvider-GoogleSheets

MCP server que expone Google Sheets como Resources (lectura), no como Tools. Segunda PoC de la serie "Aprender MCP en profundidad".

Qué expone

  • Resource estáticosheet://main/data: contenido completo de la hoja principal (MAIN_SHEET_NAME, rango MAIN_SHEET_RANGE).

  • Resource templatesheet://{sheet_name}/{cell_range}: lee cualquier hoja/rango dinámicamente. Ej: sheet://Ventas/A1:D50. Si el nombre de la hoja tiene espacios, codificarlo en la URI (ej. sheet://Hoja%201/A1:C10).

Ambos devuelven el contenido como CSV (mimeType: text/csv).

Related MCP server: emma-transactions-mcp

Setup

1. Google Cloud

  1. Crear (o reusar) un proyecto en Google Cloud Console.

  2. Habilitar la Google Sheets API para ese proyecto (APIs & Services → Enable APIs → "Google Sheets API").

  3. Crear un Service Account (IAM & Admin → Service Accounts → Create Service Account).

  4. Generar una key JSON para ese service account (pestaña "Keys" → Add Key → JSON) y descargarla.

  5. Compartir la Google Sheet con el email del service account (algo como nombre@proyecto.iam.gserviceaccount.com), con permiso de lector. Este paso se olvida siempre y produce un error 403.

2. Proyecto local

uv sync
cp .env.example .env

Completar .env:

SPREADSHEET_ID=<el ID de la spreadsheet, va en la URL entre /d/ y /edit>
GOOGLE_APPLICATION_CREDENTIALS=credentials.json
MAIN_SHEET_NAME=Sheet1
MAIN_SHEET_RANGE=A1:Z1000

Guardar la key JSON del service account como credentials.json en la raíz del proyecto (o ajustar la ruta en GOOGLE_APPLICATION_CREDENTIALS). Nunca commitear este archivo — ya está en .gitignore.

3. Correr el server

uv run python server.py

El server habla MCP sobre stdio. Para probarlo interactivamente:

uv run mcp dev server.py

Para usarlo desde Claude Desktop, agregar en claude_desktop_config.json:

{
  "mcpServers": {
    "sheets-resources": {
      "command": "uv",
      "args": ["--directory", "/ruta/absoluta/a/este/proyecto", "run", "python", "server.py"]
    }
  }
}

Reiniciar Claude Desktop y verificar que el server aparece con los dos resources listados.

Estructura

server.py           # MCP server: registra los resources
sheets_client.py     # wrapper de la Google Sheets API (auth + read_range)
.env.example         # variables de entorno de referencia
.gitignore           # excluye credentials*.json y .env

Variables de entorno

Variable

Requerida

Default

Descripción

SPREADSHEET_ID

ID de la spreadsheet a exponer

GOOGLE_APPLICATION_CREDENTIALS

No

credentials.json

Ruta a la key JSON del service account

MAIN_SHEET_NAME

No

Sheet1

Hoja que expone el resource estático

MAIN_SHEET_RANGE

No

A1:Z1000

Rango que expone el resource estático

Qué aprendí

  • Resources son application-controlled, no model-controlled: a diferencia de un Tool, el LLM no "decide ejecutar" un resource con side effects — el cliente decide qué exponer y cuándo leerlo como contexto. El server solo declara qué existe y cómo leerlo.

  • La URI es el contrato: un resource se identifica por su URI (sheet://main/data), no por un nombre de función. Eso permite que resources estáticos y templated convivan bajo el mismo esquema (sheet://{sheet_name}/{cell_range}), sin necesidad de "argumentos" en el sentido de Tools.

  • Templates son URIs con match, no RPC con parámetros validados por schema: el SDK resuelve {sheet_name} y {cell_range} vía regex sobre la URI (cada segmento sin /), y recién ahí invoca la función — es más parecido a un router HTTP que a la firma de un Tool.

  • Cuándo elegir Resource vs Tool: si la acción es "dame datos para que los uses como contexto" → Resource. Si es "hacé algo (leer con efectos, escribir, calcular, invocar una API con params arbitrarios que decide el modelo)" → Tool. Google Sheets de solo lectura calza perfecto como Resource porque no hay acción que "invocar": es data que el LLM lee, igual que leería un archivo.

alt text

Related MCP Connectors

Related MCP Servers