mcpclaudeai-agentsdata-laketutorial

Como construir un servidor MCP para tu Data Lake

Michael San Martim · 2026-04-24

MCP (Model Context Protocol) permite a los agentes de IA llamar herramientas — cómo consultar una base de datos. DataSpoc Lens incluye un servidor MCP integrado que convierte tu data lake de Parquet en una API consultable para Claude, GPT, agentes LangGraph y cualquier cliente compatible con MCP.

Este tutorial te muestra cómo pasar de datos crudos en S3 a un servidor MCP completamente funciónal en menos de 10 minutos.

El resultado final

Despues de la configuración, cualquier agente de IA puede:

  • Descubrir tablas en tu data lake
  • Inspeccionar esquemas y datos de muestra
  • Ejecutar consultas SQL con DuckDB
  • Hacer preguntas en lenguaje natural
  • Obtener métricas y KPIs preconstruidos

Todo sin código personalizado.

Paso 1: Ingestar datos con Pipe

Si tus datos ya estan en Parquet en S3/GCS/Azure, salta al Paso 2. De lo contrario, extrae de tus fuentes:

Terminal window
pip install dataspoc-pipe
dataspoc-pipe init sales-pipeline
dataspoc-pipe add postgres \
--host db.company.com \
--database sales \
--tables orders,customers,products,revenue \
--incremental updated_at \
--destination s3://company-lake
dataspoc-pipe run

Tu bucket ahora tiene:

s3://company-lake/
.dataspoc/manifest.json
raw/postgres/orders/*.parquet
raw/postgres/customers/*.parquet
raw/postgres/products/*.parquet
raw/postgres/revenue/*.parquet

Paso 2: Instalar DataSpoc Lens con MCP

Terminal window
pip install dataspoc-lens[mcp]

Esto instala el CLI principal de Lens mas las dependencias del servidor MCP.

Paso 3: Configurar e iniciar el servidor MCP

Terminal window
# Point Lens at your bucket
dataspoc-lens add-bucket s3://company-lake
# Discover tables
dataspoc-lens discover
# Found 4 tables: orders, customers, products, revenue
# Start the MCP server
dataspoc-lens mcp

Salida:

DataSpoc Lens MCP Server running
Transport: stdio
Tables: 4 discovered
Tools: 7 available
- list_tables
- get_schema
- sample_data
- query
- ask
- get_metrics
- explain_table
Waiting for MCP client connection...

Paso 4: Configurar Claude Desktop

Agrega a la configuración de Claude Desktop (~/.config/claude/claude_desktop_config.json en Linux, ~/Library/Application Support/Claude/claude_desktop_config.json en macOS):

{
"mcpServers": {
"data-lake": {
"command": "dataspoc-lens",
"args": ["mcp"],
"env": {
"AWS_PROFILE": "data-lake",
"DATASPOC_BUCKET": "s3://company-lake"
}
}
}
}

Reinicia Claude Desktop. Veras el icono de herramientas indicando 7 herramientas disponibles.

Las 7 herramientas MCP

1. list_tables — Descubrir datos disponibles

Llamada:

{
"tool": "list_tables"
}

Respuesta:

{
"tables": [
{"name": "raw.postgres.orders", "rows": 1247893, "size_mb": 340},
{"name": "raw.postgres.customers", "rows": 89421, "size_mb": 12},
{"name": "raw.postgres.products", "rows": 2431, "size_mb": 1.1},
{"name": "raw.postgres.revenue", "rows": 4201847, "size_mb": 890}
]
}

2. get_schema — Inspeccionar estructura de tabla

Llamada:

{
"tool": "get_schema",
"arguments": {"table": "raw.postgres.orders"}
}

Respuesta:

{
"table": "raw.postgres.orders",
"columns": [
{"name": "id", "type": "INTEGER", "nullable": false},
{"name": "customer_id", "type": "INTEGER", "nullable": false},
{"name": "product_id", "type": "INTEGER", "nullable": false},
{"name": "amount", "type": "DECIMAL(10,2)", "nullable": false},
{"name": "status", "type": "VARCHAR", "nullable": false},
{"name": "created_at", "type": "TIMESTAMP", "nullable": false},
{"name": "updated_at", "type": "TIMESTAMP", "nullable": false}
],
"row_count": 1247893
}

3. sample_data — Vista previa de filas

Llamada:

{
"tool": "sample_data",
"arguments": {"table": "raw.postgres.orders", "limit": 5}
}

Respuesta:

{
"table": "raw.postgres.orders",
"sample": [
{"id": 1, "customer_id": 42, "product_id": 7, "amount": 299.00, "status": "completed", "created_at": "2024-01-15T10:23:00"},
{"id": 2, "customer_id": 15, "product_id": 3, "amount": 49.99, "status": "completed", "created_at": "2024-01-15T11:05:00"},
{"id": 3, "customer_id": 42, "product_id": 12, "amount": 799.00, "status": "pending", "created_at": "2024-01-15T14:30:00"}
]
}

4. query — Ejecutar SQL

Llamada:

{
"tool": "query",
"arguments": {
"sql": "SELECT DATE_TRUNC('month', created_at) AS month, SUM(amount) AS revenue FROM raw.postgres.orders WHERE created_at >= '2024-01-01' GROUP BY 1 ORDER BY 1"
}
}

Respuesta:

{
"columns": ["month", "revenue"],
"rows": [
{"month": "2024-01-01", "revenue": 342891.50},
{"month": "2024-02-01", "revenue": 389012.75},
{"month": "2024-03-01", "revenue": 421547.00}
],
"row_count": 3,
"execution_time_ms": 234
}

5. ask — Preguntas en lenguaje natural

Llamada:

{
"tool": "ask",
"arguments": {
"question": "Which customers spent the most last quarter?"
}
}

Respuesta:

{
"answer": "The top 5 customers by spending last quarter were: Acme Corp ($89,234), GlobalTech ($67,891), Initech ($54,320), Umbrella Inc ($48,900), and Wayne Enterprises ($45,670).",
"sql": "SELECT c.name, SUM(o.amount) AS total_spent FROM raw.postgres.orders o JOIN raw.postgres.customers c ON o.customer_id = c.id WHERE o.created_at >= '2024-07-01' AND o.created_at < '2024-10-01' GROUP BY c.name ORDER BY total_spent DESC LIMIT 5",
"data": [
{"name": "Acme Corp", "total_spent": 89234.00},
{"name": "GlobalTech", "total_spent": 67891.00},
{"name": "Initech", "total_spent": 54320.00},
{"name": "Umbrella Inc", "total_spent": 48900.00},
{"name": "Wayne Enterprises", "total_spent": 45670.00}
]
}

6. get_metrics — KPIs preconstruidos

Llamada:

{
"tool": "get_metrics",
"arguments": {"period": "last_30_days"}
}

Respuesta:

{
"period": "2024-09-15 to 2024-10-15",
"metrics": {
"total_revenue": 487293.00,
"order_count": 12847,
"avg_order_value": 37.93,
"unique_customers": 3421,
"new_customers": 289
}
}

7. explain_table — Documentacion de datos

Llamada:

{
"tool": "explain_table",
"arguments": {"table": "raw.postgres.orders"}
}

Respuesta:

{
"table": "raw.postgres.orders",
"description": "Transaction records from the e-commerce platform. Each row represents one purchase.",
"columns": {
"id": "Unique order identifier",
"customer_id": "FK to customers table",
"amount": "Total order value in USD",
"status": "One of: pending, completed, refunded, cancelled",
"created_at": "When the order was placed"
},
"relationships": ["customers (customer_id)", "products (product_id)"],
"common_queries": [
"Revenue by month: SELECT DATE_TRUNC('month', created_at), SUM(amount) FROM orders GROUP BY 1",
"Orders by status: SELECT status, COUNT(*) FROM orders GROUP BY 1"
]
}

Conversacion multi-turno realista con un agente

Asi se ve cuando Claude usa el servidor MCP:

Usuario: “Como esta la tendencia de retencion? Estamos perdiendo clientes?”

Llamadas internas de herramientas de Claude:

  1. Llama a list_tables para ver que datos estan disponibles
  2. Llama a get_schema("raw.postgres.orders") para entender la estructura de ordenes
  3. Llama a get_schema("raw.postgres.customers") para verificar fechas de registro
  4. Llama a query con:
WITH monthly_cohorts AS (
SELECT
DATE_TRUNC('month', c.created_at) AS cohort_month,
DATE_TRUNC('month', o.created_at) AS order_month,
COUNT(DISTINCT o.customer_id) AS active_customers
FROM raw.postgres.customers c
JOIN raw.postgres.orders o ON c.id = o.customer_id
WHERE c.created_at >= '2024-01-01'
GROUP BY 1, 2
),
cohort_sizes AS (
SELECT cohort_month, COUNT(DISTINCT id) AS cohort_size
FROM raw.postgres.customers
WHERE created_at >= '2024-01-01'
GROUP BY 1
)
SELECT
mc.cohort_month,
mc.order_month,
mc.active_customers,
cs.cohort_size,
ROUND(mc.active_customers::FLOAT / cs.cohort_size * 100, 1) AS retention_pct
FROM monthly_cohorts mc
JOIN cohort_sizes cs ON mc.cohort_month = cs.cohort_month
ORDER BY mc.cohort_month, mc.order_month

Respuesta de Claude:

Analizando los datos de retencion por cohorte, esta es la tendencia:

CohorteMes 1Mes 2Mes 3Mes 6
Ene 2024100%68%52%34%
Abr 2024100%71%55%38%
Jul 2024100%74%59%

Buenas noticias: la retencion esta mejorando. La retencion del Mes 2 paso de 68% a 74% a lo largo del ano. Los cambios en el producto del Q2 (onboarding autoservicio) parecen estar funciónando.

Sin embargo, la caida al 34% en el Mes 6 sugiere que perdemos clientes alrededor de la marca de 6 meses — posiblemente cuando los contratos anuales llegan a renovacion.

Modelo de seguridad

El servidor MCP es solo lectura por diseno:

  • No se permiten sentencias INSERT, UPDATE, DELETE, DROP o CREATE
  • Las consultas se validan antes de la ejecucion
  • El servidor se ejecuta con los permisos IAM del proceso (tu perfil de AWS)
  • El control de acceso a nivel de bucket significa que los agentes solo ven datos que estan autorizados a ver
Terminal window
# Agent can only access buckets your IAM role permits
export AWS_PROFILE=analyst # Has access to s3://company-product only
dataspoc-lens mcp # Only exposes tables in permitted buckets

No hay API keys que gestionar. No hay tokens de autenticacion. Solo IAM.

SDK de Python para CrewAI / LangGraph

Si estas construyendo agentes en Python en lugar de usar Claude Desktop, usa el SDK directamente:

from dataspoc_lens import LensClient
# Initialize (reads from same config as CLI)
client = LensClient(bucket="s3://company-lake")
# Same capabilities as MCP tools
tables = client.list_tables()
schema = client.get_schema("raw.postgres.orders")
result = client.query("SELECT COUNT(*) FROM raw.postgres.orders")
answer = client.ask("What's our churn rate?")

Integracion con CrewAI

from crewai import Agent, Task, Crew
from crewai_tools import tool
from dataspoc_lens import LensClient
client = LensClient()
@tool
def query_data_lake(sql: str) -> str:
"""Execute a SQL query against the company data lake."""
result = client.query(sql)
return str(result)
@tool
def discover_tables() -> str:
"""List all available tables in the data lake."""
tables = client.list_tables()
return "\n".join([f"{t['name']} ({t['rows']} rows)" for t in tables])
analyst = Agent(
role="Data Analyst",
goal="Answer business questions using SQL on the data lake",
tools=[query_data_lake, discover_tables],
llm="gpt-4o",
)
task = Task(
description="Analyze customer lifetime value by acquisition channel",
agent=analyst,
)
crew = Crew(agents=[analyst], tasks=[task])
result = crew.kickoff()

Integracion con LangGraph

Consulta el tutorial completo: Construyendo un agente analista de datos con LangGraph.

El patrón AGENT.md

Para agentes que trabajan de forma autonoma con tu data lake, crea un archivo AGENT.md que describa los datos disponibles:

# Data Lake Agent Instructions
## Available Data
You have access to a data lake via the DataSpoc Lens MCP server.
## Tables
- `raw.postgres.orders` — All orders (1.2M rows). Key columns: customer_id, amount, status, created_at
- `raw.postgres.customers` — Customer profiles (89K rows). Key columns: name, email, plan, created_at
- `raw.postgres.products` — Product catalog (2.4K rows). Key columns: name, category, price
- `curated.finance.revenue` — Monthly revenue rollups (4.2M rows). Key columns: month, mrr, arr, churn_rate
## Common Queries
- Revenue by month: `SELECT DATE_TRUNC('month', created_at), SUM(amount) FROM raw.postgres.orders GROUP BY 1`
- Active customers: `SELECT COUNT(DISTINCT customer_id) FROM raw.postgres.orders WHERE created_at > CURRENT_DATE - INTERVAL '30 days'`
- Churn: `SELECT month, churn_rate FROM curated.finance.revenue ORDER BY month DESC LIMIT 12`
## Rules
- Always use the `query` tool for exact numbers
- Use `ask` for exploratory questions when you're not sure about the schema
- Never modify data — all queries are read-only
- When presenting numbers, always show the SQL you used (for auditability)

Coloca esto en la raiz de tu proyecto. Los agentes que leen el contexto del proyecto (Claude Code, Cursor, Cline) lo usaran para entender cómo interactuar con tus datos.

Ejecucion en producción

Para despliegues en producción, ejecuta el servidor MCP cómo un proceso persistente:

Terminal window
# systemd service
[Unit]
Description=DataSpoc Lens MCP Server
After=network.target
[Service]
Type=simple
User=dataspoc
ExecStart=/usr/local/bin/dataspoc-lens mcp --transport sse --port 8080
Environment=AWS_PROFILE=data-lake
Environment=DATASPOC_BUCKET=s3://company-lake
Restart=always
[Install]
WantedBy=multi-user.target

O con Docker:

FROM python:3.11-slim
RUN pip install dataspoc-lens[mcp]
ENV DATASPOC_BUCKET=s3://company-lake
CMD ["dataspoc-lens", "mcp", "--transport", "sse", "--port", "8080"]
Terminal window
docker run -d \
-p 8080:8080 \
-e AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY \
-e DATASPOC_BUCKET=s3://company-lake \
dataspoc-lens-mcp

Resumen

En 4 pasos, convertiste un monton de archivos Parquet en una API inteligente para agentes de IA:

  1. Ingesta datos con Pipe (o trae tu propio Parquet)
  2. Instala dataspoc-lens[mcp]
  3. Inicia dataspoc-lens mcp
  4. Conecta Claude Desktop, LangGraph, CrewAI o cualquier cliente MCP

Tu data lake ahora es una herramienta de primera clase para cualquier agente de IA — descubrible, consultable y segura.

Recomendados