SignalK MCP Server

Proporciona a los agentes de IA acceso de solo lectura a los sistemas de datos marinos SignalK, permitiendo consultas de datos de navegación de embarcaciones, objetivos AIS y alarmas del sistema.

Documentación

Servidor MCP de SignalK

Un servidor de Model Context Protocol (MCP) que proporciona a los agentes de IA un acceso eficiente a los datos marinos de SignalK mediante ejecución de código en aislamientos V8. Este enfoque reduce el uso de tokens en un 90-96% en comparación con las herramientas MCP tradicionales.

🚀 Versión 1.0.6: ¡Ahora con motor de ejecución de código para un ahorro masivo de tokens! Consulta CHANGELOG.md para más detalles.

¿Por qué ejecución de código?

Las herramientas MCP tradicionales devuelven TODOS los datos a la IA, consumiendo cantidades masivas de tokens. Este servidor utiliza aislamientos V8 (como Cloudflare Workers) para permitir que los agentes de IA ejecuten código JavaScript que filtra los datos antes de devolverlos.

Ahorro de tokens:

  • Consultas de estado de la embarcación: 94% de reducción (2,000 → 120 tokens)
  • Filtrado de objetivos AIS: 95% de reducción (10,000 → 500 tokens)
  • Flujos de trabajo con múltiples llamadas: 97% de reducción (13,000 → 300 tokens)

Inicio rápido

Instalación

# Via npx (recommended)
npx signalk-mcp-server

# Or install globally
npm install -g signalk-mcp-server

Configuración de Claude Desktop

Añade a tu configuración de Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json en macOS):

{
  "mcpServers": {
    "signalk": {
      "command": "npx",
      "args": ["signalk-mcp-server"],
      "env": {
        "SIGNALK_HOST": "localhost",
        "SIGNALK_PORT": "3000",
        "SIGNALK_TLS": "false"
      }
    }
  }
}

Uso básico

Consulta del agente de IA: "¿Cuál es la posición de mi embarcación y los 3 objetivos AIS más cercanos?"

Ejecución de código (automática):

(async () => {
  // Get vessel position
  const vessel = await getVesselState();
  const position = vessel.data["navigation.position"]?.value;

  // Get AIS targets and filter in isolate
  const ais = await getAisTargets({ pageSize: 50 });
  const closest = ais.targets.slice(0, 3);

  return JSON.stringify({ position, closest });
})()
// Returns: ~300 tokens (97% savings vs legacy tools!)

Características

Motor de ejecución de código

  • Aislamiento V8: Ejecución segura de JavaScript
  • Filtrado en el cliente: Procesa los datos antes de devolverlos a la IA
  • Múltiples llamadas a API: Combina operaciones en una sola ejecución
  • 90-96% de ahorro de tokens: Reducción masiva en el uso del contexto
  • Sobrecarga inferior a 100ms: Ejecución rápida con límites de memoria y tiempo

Funciones disponibles del SDK

Al usar execute_code, estas funciones están disponibles. IMPORTANTE: TODAS las funciones son asíncronas y DEBEN esperarse con await:

// Vessel data
const vessel = await getVesselState();

// AIS targets (with pagination and optional distance filter)
const ais = await getAisTargets({ page: 1, pageSize: 50, maxDistance: 5000 });

// System alarms
const alarms = await getActiveAlarms();

// Discover available data paths
const paths = await listAvailablePaths();

// Get specific path value (both string and object syntax work)
const speed = await getPathValue("navigation.speedOverGround");
const heading = await getPathValue({ path: "navigation.headingTrue" });

// Connection status - ALSO requires await!
const status = await getConnectionStatus();

Datos marinos en tiempo real

  • Posición de la embarcación, rumbo, velocidad, viento
  • Seguimiento de objetivos AIS con cálculos de distancia
  • Notificaciones y alarmas del sistema
  • Descubrimiento dinámico de rutas SignalK
  • Monitoreo de salud de la conexión

Configuración

Variables de entorno

# SignalK Connection (Required)
SIGNALK_HOST=localhost          # SignalK server hostname/IP
SIGNALK_PORT=3000              # SignalK server port
SIGNALK_TLS=false              # Use WSS/HTTPS (true/false)

# Execution Mode (Optional)
EXECUTION_MODE=code            # code (default) | tools (legacy) | hybrid

# Optional Settings
SERVER_NAME=signalk-mcp-server
SERVER_VERSION=1.0.6

Modos de ejecución

ModoDescripciónCaso de uso
code (predeterminado)Solo ejecución en aislamiento V8Uso en producción, máxima eficiencia
toolsHerramientas MCP heredadasCompatibilidad hacia atrás
hybridAmbos enfoques disponiblesPeríodo de migración

Ejemplos

Ejemplo 1: Datos de embarcación filtrados

Consulta: "Obtén el nombre y la posición de mi embarcación"

Código:

(async () => {
  const vessel = await getVesselState();
  return JSON.stringify({
    name: vessel.data.name?.value,
    position: vessel.data["navigation.position"]?.value
  });
})()

Resultado: ~200 tokens (frente a 2,000 con herramientas heredadas)

Ejemplo 2: Embarcaciones cercanas

Consulta: "Muestra embarcaciones dentro de 1 milla náutica"

Código:

(async () => {
  const ais = await getAisTargets({ pageSize: 50 });

  // Filter in isolate - huge savings!
  const nearby = ais.targets.filter(t =>
    t.distanceMeters && t.distanceMeters < 1852
  );

  return JSON.stringify({
    total: ais.count,
    nearby: nearby.length,
    vessels: nearby.slice(0, 5)
  });
})()

Resultado: ~300 tokens (frente a 10,000 con herramientas heredadas)

Ejemplo 3: Solo alarmas críticas

Consulta: "¿Hay alguna alarma crítica?"

Código:

(async () => {
  const alarms = await getActiveAlarms();

  const critical = alarms.alarms.filter(a =>
    a.state === "alarm" || a.state === "emergency"
  );

  return JSON.stringify({
    hasCritical: critical.length > 0,
    count: critical.length,
    details: critical
  });
})()

Resultado: ~100 tokens (frente a 1,000 con herramientas heredadas)

Ejemplo 4: Flujo de trabajo con múltiples llamadas

Consulta: "Dame un informe de situación"

Código:

(async () => {
  // All calls in ONE execution!
  const vessel = await getVesselState();
  const ais = await getAisTargets({ pageSize: 50 });
  const alarms = await getActiveAlarms();

  // Process everything in isolate
  const closeVessels = ais.targets.filter(t =>
    t.distanceMeters && t.distanceMeters < 1852
  ).length;

  const criticalAlarms = alarms.alarms.filter(a =>
    a.state === "alarm" || a.state === "emergency"
  ).length;

  return JSON.stringify({
    position: vessel.data["navigation.position"]?.value,
    speed: vessel.data["navigation.speedOverGround"]?.value,
    vesselsNearby: closeVessels,
    criticalAlarms: criticalAlarms
  });
})()

Resultado: ~300 tokens (frente a 13,000 con 3 llamadas de herramientas separadas)

Desarrollo

Requisitos previos

  • Node.js 18.0.0 o superior
  • Acceso a un servidor SignalK

Configuración

# Clone repository
git clone <repository-url>
cd signalk-mcp-server

# Install dependencies
npm install

# Build
npm run build

# Run tests
npm run test:unit

# Run in development mode
npm run dev

Pruebas

# Unit tests (fast)
npm run test:unit

# Integration tests (requires live SignalK server)
npm run test:e2e

# Full CI pipeline
npm run ci

Arquitectura

Flujo de ejecución de código

AI Agent
  ↓
execute_code tool
  ↓
V8 Isolate Sandbox (isolated-vm)
  ↓
SignalK SDK Functions (all async, must await)
  ↓
SignalK Binding Layer (RPC-style)
  ↓
SignalK Client (HTTP REST API)
  ↓
SignalK Server

Nota: El modo solo HTTP garantiza datos frescos en cada solicitud. El código WebSocket se conserva para soporte futuro de streaming.

Componentes clave

  • Aislamiento (src/execution-engine/isolate-sandbox.ts): Ejecución segura en aislamiento V8
  • Enlace SignalK (src/bindings/signalk-binding.ts): Invocación de métodos estilo RPC
  • Generador de SDK (src/sdk/generator.ts): Genera automáticamente el SDK a partir de definiciones de herramientas
  • Cliente SignalK (src/signalk-client.ts): Cliente HTTP/WebSocket para SignalK

Seguridad

  • Aislamiento completo: Sin acceso a los globales de Node.js
  • Límites de memoria: 128MB por ejecución
  • Protección de tiempo de espera: Máximo 30s de tiempo de ejecución
  • Sin exposición de credenciales: La autenticación de SignalK la maneja la capa de enlace
  • Solo lectura: Sin operaciones de escritura en el servidor SignalK

Migración desde 1.x

Cambios importantes

La versión 1.0.6 cambia el modo predeterminado de hybrid a code. Las herramientas heredadas ya no están disponibles por defecto.

Compatibilidad hacia atrás

Para usar herramientas heredadas, configura el modo de ejecución:

{
  "mcpServers": {
    "signalk": {
      "env": {
        "EXECUTION_MODE": "tools"
      }
    }
  }
}

Guía de migración

Consulta TOOL-MIGRATION-GUIDE.md para ejemplos completos de migración.

Antes (heredado):

Tool: get_vessel_state
Returns: All vessel data (~2000 tokens)

Después (código):

(async () => {
  const vessel = await getVesselState();
  return JSON.stringify({
    name: vessel.data.name?.value,
    position: vessel.data["navigation.position"]?.value
  });
})()
// Returns: ~200 tokens

Solución de problemas

Problemas de conexión

Verifica el estado de la conexión (nota: await es obligatorio):

(async () => {
  const status = await getConnectionStatus();  // await is required!
  return JSON.stringify(status);
})()

Modo heredado

Si necesitas herramientas heredadas temporalmente:

EXECUTION_MODE=tools npx signalk-mcp-server

Modo de depuración

Habilita el registro detallado:

DEBUG=true
LOG_LEVEL=debug

Contribuciones

¡Las contribuciones son bienvenidas! Consulta CONTRIBUTING.md para las pautas.

Licencia

Licencia MIT - consulta LICENSE para más detalles.

Recursos

Créditos

Construido con:


🚢 ¡Feliz navegación con datos marinos impulsados por IA!