structured.sh

Servidor MCP autoalojado para memoria persistente de agentes. Define esquemas tipados, escribe registros y consulta con SQL mediante DuckDB sobre archivos Parquet en disco.

Documentación

■ structured
memoria nativa de esquema para agentes de IA

structured.sh · Inicio rápido · Conectar con Claude · Herramientas MCP · Referencia de API · Desplegar


Define esquemas. Escribe datos estructurados. Consulta con SQL. Todo como archivos Parquet que tú posees.

docker compose up

¿Qué es esto?

Structured brinda a los agentes de IA (y a los humanos) memoria persistente y consultable:

  1. Define una memoria — nombre + esquema tipado (como una tabla)
  2. Escribe registros — almacenados en búfer y vaciados automáticamente a archivos Parquet
  3. Consulta con SQL — DuckDB se ejecuta directamente sobre los archivos Parquet
  4. Posee tus datos — todo son archivos locales en disco, sin dependencia de proveedor

Funciona con Claude Desktop, Cursor, Windsurf, Cline o cualquier cliente compatible con MCP.

Arquitectura

┌──────────────────────────────────────────────────────┐
│                 docker compose up                     │
│                                                       │
│  ┌──────────┐    ┌──────────────┐    ┌────────────┐  │
│  │Dashboard │    │   REST API   │    │ MCP Server │  │
│  │  :3000   │───▶│    :3001     │◀───│   stdio    │  │
│  │          │    │              │    │            │  │
│  │Vite+React│    │ Hono + WASM  │    │  9 tools   │  │
│  └──────────┘    │              │    └────────────┘  │
│                  │ SQLite  (sql.js)                   │
│                  │ DuckDB  (wasm)                     │
│                  │ Parquet (tiny-parquet)              │
│                  └──────┬───────┘                     │
│                         │                             │
│                    ./data/                             │
│                  ├── structured.db    ← metadata       │
│                  └── parquet/         ← your data      │
│                      ├── user_prefs/                   │
│                      │   └── 2026/04/09/...parquet    │
│                      └── campaign_data/                │
│                          └── 2026/04/09/...parquet    │
└──────────────────────────────────────────────────────┘

Cero dependencias nativas. Todo se ejecuta en WASM: sin compilaciones de C++, sin problemas de plataforma.

Inicio rápido

1. Clona y configura

git clone https://github.com/structured-sh/structured.git
cd structured

Edita docker-compose.yml y establece tus credenciales:

environment:
  - API_KEY=your-secret-api-key        # Used by MCP clients & scripts
  - DASHBOARD_PASSWORD=your-password   # Protects the dashboard UI

Dos credenciales separadas:

  • API_KEY — autenticación de máquina para clientes MCP, scripts e ingesta de analíticas
  • DASHBOARD_PASSWORD — autenticación humana para el panel web. Déjalo sin configurar para deshabilitar el inicio de sesión (uso solo local).

2. Inicia el stack

docker compose up -d
ServicioURL
Dashboardhttp://localhost:3000
APIhttp://localhost:3001
MCPstdio (conectado automáticamente)

3. Crea una memoria

curl -X POST http://localhost:3001/memories \
  -H "Authorization: Bearer your-secret-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "user_preferences",
    "fields": [
      { "name": "key", "type": "string" },
      { "name": "value", "type": "string" },
      { "name": "priority", "type": "int32" }
    ],
    "description": "User preference settings"
  }'

4. Escribe datos

curl -X POST http://localhost:3001/memories/user_preferences/write \
  -H "Authorization: Bearer your-secret-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "data": [
      { "key": "theme", "value": "dark", "priority": 1 },
      { "key": "language", "value": "en", "priority": 2 }
    ]
  }'

5. Consulta con SQL

curl -X POST http://localhost:3001/query \
  -H "Authorization: Bearer your-secret-api-key" \
  -H "Content-Type: application/json" \
  -d '{ "sql": "SELECT * FROM user_preferences ORDER BY priority" }'

Los nombres de memoria funcionan como nombres de tabla: DuckDB los resuelve a archivos Parquet automáticamente.

6. Accede a los archivos sin procesar

# Files on disk
ls ./data/parquet/user_preferences/

# DuckDB CLI
duckdb -c "SELECT * FROM read_parquet('./data/parquet/user_preferences/**/*.parquet')"

# Python
import duckdb
duckdb.sql("SELECT * FROM './data/parquet/user_preferences/**/*.parquet'").show()

Conectar con Claude / Cursor

Local (Docker)

Añade a ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "structured": {
      "command": "docker",
      "args": ["exec", "-i", "structured-mcp", "node", "index.js"]
    }
  }
}

Para Cursor, añade en Configuración → Funciones → Servidores MCP:

{
  "structured": {
    "command": "docker",
    "args": ["exec", "-i", "structured-mcp", "node", "index.js"]
  }
}

Cloud (structured.sh)

Próximamente: versión alojada en structured.sh

{
  "mcpServers": {
    "structured": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/mcp-proxy", "https://mcp.structured.sh"]
    }
  }
}

Herramientas MCP

Una vez conectado, simplemente habla con naturalidad. La IA elige la herramienta adecuada.

HerramientaQué decir
create_memory"Crea una memoria para registrar ventas diarias con campos: fecha, ingresos, unidades"
list_memories"¿Qué memorias tengo?"
describe_memory"Muéstrame el esquema de daily_sales"
write_memory"Guarda las ventas de hoy: date=2026-04-09, revenue=1250.50, units=42"
query_memory"¿Cuál es el ingreso total de este mes?"
store_document"Recuerda esta configuración para más tarde"
get_document"Obtén el documento abc-123"
flush_memory"Vacía todos los datos pendientes al disco"
delete_memory"Elimina la memoria test_data"

Ingesta de datos desde tus aplicaciones

Usa las plantillas en templates/ para enviar eventos desde sistemas externos:

PlantillaCaso de uso
templates/ingest-app-analytics.jsEventos de aplicaciones móviles/web (instalaciones, acciones, compras)
templates/ingest-webhook.jsWebhooks de Stripe, GitHub, Shopify
templates/query-report.jsGenera informes SQL → terminal, Markdown o Slack
// Example: track an install from your iOS app
import { track } from './templates/ingest-app-analytics.js';
await track('install', 'user_abc', { platform: 'ios', app_version: '1.0.0' });

Luego consulta todos tus eventos:

SELECT event, COUNT(*) as n, COUNT(DISTINCT user_id) as users
FROM app_events
WHERE timestamp > now() - INTERVAL '30 days'
GROUP BY event ORDER BY n DESC

Cola de mensajes fallidos

Los registros rechazados por los modos de esquema strict o evolve no se descartan: se escriben automáticamente en _dlq_{memory_name} para su inspección:

-- See what was rejected and why
SELECT _reason, _payload, _rejected_at
FROM _dlq_app_events
ORDER BY _rejected_at DESC
LIMIT 20

Rotación de clave API

Rota tu clave API en cualquier momento desde la página Conectar del panel sin reiniciar:

  1. Ve a la sección ConectarClave API
  2. Haz clic en Rotar clave
  3. Copia la nueva clave (se muestra una sola vez)
  4. Actualiza tu configuración MCP y cualquier script

La clave anterior se invalida inmediatamente.

Referencia de API

Autenticación (Panel)

MétodoRutaDescripción
GET/auth/statusComprueba si la autenticación del panel está habilitada
POST/auth/loginInicia sesión con { password }, devuelve token de sesión
GET/auth/meValida la sesión actual (cabecera X-Session-Token)
POST/auth/logoutCierra sesión (el cliente descarta el token)

Memorias

MétodoRutaDescripción
GET/memoriesLista todas las memorias
POST/memoriesCrea una memoria
GET/memories/:nameObtén detalles de la memoria
PUT/memories/:nameActualiza la memoria
DELETE/memories/:nameElimina la memoria
POST/memories/:name/writeEscribe registros
POST/memories/:name/flushVacía a Parquet
GET/memories/:name/previewVista previa de datos
GET/memories/:name/filesLista archivos Parquet

Consulta

MétodoRutaDescripción
POST/queryEjecuta SQL de DuckDB

Almacenamiento (Documentos)

MétodoRutaDescripción
POST/documentsAlmacena un documento JSON
GET/documents/collectionsLista colecciones
GET/documents/:collectionLista documentos
DELETE/documents/:collection/:idElimina documento

Configuración

MétodoRutaDescripción
GET/settings/api-keyObtén la clave API actual enmascarada
POST/settings/rotate-keyGenera una nueva clave API

Archivos

MétodoRutaDescripción
GET/files/*Descarga archivo Parquet sin procesar

MCP (SSE)

MétodoRutaDescripción
GET/sseFlujo SSE para clientes MCP
POST/messagesMensajes JSON-RPC

Modos de esquema

ModoComportamiento
flexAcepta todos los campos, sin validación (predeterminado)
evolveAcepta todos, detecta y registra desviaciones de esquema
strictRechaza registros con campos no coincidentes → DLQ

Tipos de campo

TipoTipo ParquetNotas
stringBYTE_ARRAY (UTF-8)Predeterminado
int32INT32
int64INT64
float32FLOAT
float64DOUBLE
booleanBOOLEAN
timestampINT64 (millis)ms Unix, UTC

Stack

Solo 7 paquetes npm. Sin complementos nativos: todo se ejecuta en WASM o JS puro.

PaqueteQué hace
hono + @hono/node-serverEnrutador HTTP: API rápida y estándar web
@duckdb/duckdb-wasmMotor de consultas SQL, se ejecuta completamente en WASM
sql.jsSQLite en WASM: almacena metadatos de esquema
tiny-parquetEscritor Parquet en JS puro, cero dependencias nativas
@modelcontextprotocol/sdkRegistro de servidor/herramientas MCP
zodValidación de esquema para entradas de API

Runtime: Node.js ≥ 20

Como todo se ejecuta en WASM, no hay compilaciones de C++, no hay node-gyp, no hay binarios específicos de plataforma. La imagen de Docker funciona en cualquier arquitectura que Docker soporte.

Desarrollo

# Local dev (no Docker)
cd api && npm install && node index.js
cd dashboard && npm install && npm run dev

# Full stack
docker compose up --build

Licencia

Apache 2.0


Construido con tiny-parquet · Impulsado por DuckDB · structured.sh