Network Table MCP
Servidor MCP que expone FRC NetworkTables (NT4) a agentes de IA. Lee, escribe y monitorea las tablas de red de un robot.
Documentación
nt-mcp-server
Un servidor MCP independiente para leer, escribir y monitorear datos de FRC NetworkTables. Permite que un agente de IA hable con las tablas de red de un robot mediante el protocolo NetworkTables. El objetivo principal es la simulación local de RobotPy (python -m robotpy sim en 127.0.0.1:5810).
dependencias fijadas (fastmcp==3.4.7, pyntcore==2026.2.2).
Ejecutar el servidor
uv run nt-mcp-server
O, de manera equivalente, desde un checkout sin el shim de uv:
python -m nt_mcp_server
El servidor se ejecuta en stdio, que es como los clientes MCP (como opencode) se comunican con él.
Conectar a la simulación NetworkTables de RobotPy
La simulación debe estar ejecutándose antes de que el servidor pueda leer o escribir algo útil. Iníciala desde su propio proyecto y venv:
cd <path-to-try-robotpy> && .venv\Scripts\activate && python -m robotpy sim
El servidor se conecta a 127.0.0.1:5810 por defecto, que es donde escucha la simulación.
Conectar a NetworkTables de un robot real
En la mayoría de los casos, solo graba NetworkTables y usa el mcp para analizar las grabaciones.
Si quieres conectarte a las NetworkTables de un robot real en tiempo real, necesitas tener 2 adaptadores de red en tu dispositivo: uno para Internet y otro para la comunicación con el robot. Un enfoque es usar tu adaptador inalámbrico para conectarte al wifi y usar un cable ethernet para conectarte al robot. Alternativamente, puedes obtener un adaptador de red USB como segundo adaptador. En cualquier caso, es posible que necesites configurar el enrutamiento de red de tu dispositivo.
Registrar en cualquier agente
El servidor es un paquete ejecutable con uvx desde git, por lo que cualquier cliente MCP puede lanzarlo sin un checkout local ni un venv preconstruido. Ejecútalo bajo demanda:
uvx --from git+https://github.com/Mzzj114/nt-mcp-server.git nt-mcp-server
O instala el script de consola una vez y ejecútalo en cualquier lugar:
uv tool install "git+https://github.com/Mzzj114/nt-mcp-server.git"
uvx nt-mcp-server
Añade esta entrada a la configuración MCP de tu agente (mostrada aquí como el opencode.jsonc a nivel de proyecto de opencode):
{
"mcp": {
"nt": {
"type": "local",
"command": [
"uvx",
"--from",
"git+https://github.com/Mzzj114/nt-mcp-server.git",
"nt-mcp-server"
],
"enabled": true
}
}
}
Verifica con opencode mcp list desde la raíz del proyecto: el servidor nt debería mostrarse como conectado.
Cargar la habilidad nt-mcp-workflow
El repositorio incluye una habilidad de agente en skills/nt-mcp-workflow/ que enseña a un agente cómo ejecutar una investigación de NetworkTables (en vivo, reproducción sin conexión y grabación). opencode no escanea un directorio .agents/skills local del proyecto — solo carga automáticamente ~/.agents/skills, ~/.claude/skills, el .opencode/skill(s)/ del proyecto y los directorios listados bajo skills.paths explícito. Añade este bloque a tu opencode.jsonc (el mismo archivo que la entrada mcp anterior):
{
"skills": {
"paths": ["../nt-mcp-server/skills"]
}
}
La ruta relativa se resuelve contra el directorio que contiene el archivo de configuración, así que ajústala a donde esté tu checkout de este repositorio en relación con esa configuración. opencode escanea skills.paths recursivamente en busca de **/SKILL.md, por lo que apuntar al directorio skills del repositorio expone nt-mcp-workflow.
opencode carga su configuración una vez al inicio y no recarga en caliente — reinicia opencode después de editar la configuración para que la habilidad aparezca.
Grabar NetworkTables a NDJSON (sin conexión)
El CLI nt-recorder se conecta a un servidor NT4 en vivo y escribe eventos de valor en un archivo .ndjson con marca de tiempo. Se ejecuta en la laptop de desarrollo y lee NT de la simulación o del robot; no se necesitan cambios en el lado del robot.
uv run nt-recorder --prefixes /SmartDashboard/ --output-dir recordings
O, sin checkout local, ejecútalo directamente desde git mediante uvx (la misma fuente que el servidor):
uvx --from git+https://github.com/Mzzj114/nt-mcp-server.git nt-recorder --prefixes /SmartDashboard/ --output-dir recordings
O instala la herramienta una vez para que tanto nt-mcp-server como nt-recorder estén en PATH, y luego ejecuta cualquiera sin volver a descargar:
uv tool install "git+https://github.com/Mzzj114/nt-mcp-server.git"
nt-recorder --prefixes /SmartDashboard/ --output-dir recordings
El grabador es un script de consola independiente, separado del servidor MCP — ejecutar el servidor mediante uvx no lo inicia, y el agente no necesita estar conectado para grabar.
Opciones:
--prefixes— prefijos de temas a los que suscribirse (predeterminado:/)--output-dir— directorio para archivos de salida (predeterminado:./recordings)--duration— grabar durante N segundos y luego salir (predeterminado: ejecutar hasta Ctrl+C)--team— conectar mediante número de equipo en lugar de IP/puerto del servidor--server-ip/--server-port— dirección del servidor NT4 (predeterminado:127.0.0.1:5810)--identity— cadena de identidad del cliente (predeterminado:nt-recorder)--quiet— suprimir la salida de estado en stderr
Los archivos de salida se nombran nt-record-<YYYY-MM-DDTHHMMSSZ>.ndjson (sin dos puntos, seguro para Windows). Cada línea es {"time": float, "topic": str, "value": jsonable}. Códigos de salida: 0 limpio, 1 fallo de conexión, 2 error de disco/IO.
Ejecuta
uv cache pruneouv cache clearsi no quieres que los archivos de caché permanezcan en tu dispositivo después deuvx.
Herramientas
El servidor expone 18 herramientas (13 en vivo + 5 sin conexión). Cada respuesta de herramienta en vivo incluye una marca connected.
Herramientas en vivo
| Herramienta | Descripción |
|---|---|
nt_connect | Inicia el cliente NT4 y espera una conexión en vivo. Pasa exactamente un objetivo: team_number, o server_ip/server_port con el server_ip predeterminado. Parámetros: server_ip="127.0.0.1", server_port=5810, team_number=None, identity="nt-mcp", timeout_seconds=5.0. El éxito devuelve {"connected": true, "status": "connected", "target": {...}} donde target informa el objetivo resuelto (por ejemplo, {"kind": "server", "server_ip": "127.0.0.1", "server_port": 5810} o {"kind": "team", "team_number": 8326, "server_port": 5810}). Dos rechazos devuelven {"connected": false, "error": ...}: un objetivo ambiguo (tanto team_number como un server_ip no predeterminado) se rechaza antes de cualquier cambio de estado, y re-apuntar un cliente en ejecución se rechaza — llama a nt_disconnect primero. En tiempo de espera, la respuesta añade diagnósticos connections, elapsed_seconds y un hint de enrutamiento. La ruta team_number resuelve direcciones de robot mediante la búsqueda de número de equipo de pyntcore; la lista exacta de direcciones aún no se ha verificado contra hardware real, por lo que el target resuelto se informa en lugar de asumirse. |
nt_disconnect | Detiene el cliente NT4 y elimina las suscripciones persistentes. Devuelve {"connected": false, "status": "disconnected"}. |
nt_connection_info | Devuelve el estado de la conexión: {"connected": bool, "connections": [{"remote_id", "remote_ip", "last_update"}], "target": resolved_target | null, "version": str}. target es el objetivo de conexión resuelto (null antes de la primera conexión); version es la versión del paquete instalado ("unknown" cuando los metadatos están ausentes). |
nt_get | Devuelve el valor normalizado a JSON de un tema. Respuesta: {"connected": bool, "value": jsonable | null}. |
nt_get_multiple | Devuelve cada tema solicitado. Respuesta: {"connected": bool, "values": {topic: value}}. |
nt_get_info | Devuelve metadatos del tema. Respuesta: {"connected": bool, "info": {name, type_str, properties} | null}. |
nt_set | Publica un valor. Respuesta: {"connected": bool, "ok": bool, "warning": str | null}. Añade strict_type_check=True para rechazar discrepancias de tipo. |
nt_set_multiple | Escribe cada par {topic: value}. Respuesta: {"connected": bool, "results": {...}, "warnings": {...}}. |
nt_list_topics | Lista nombres de temas, filtrados por prefix, regex y/o wildcard. Respuesta: {"connected": bool, "topics": [...]}. |
nt_subscribe | Muestrea actualizaciones bajo prefijos durante duration segundos. Cambio importante: el parámetro format se eliminó en favor de output, que por defecto es "file" — la misma ventana se captura en una grabación NDJSON (formato nt-recorder, escrita en output_dir o NT_RECORDINGS_DIR) y la respuesta es un recibo compacto sin valores de muestra. Modos en línea: output="summary" devuelve min/max/mean/último por tema; output="samples" devuelve {topic: [{"time", "value"}, ...]} crudos. Ambos modos en línea están limitados por limit (por tema), max_rows (total, predeterminado 5000) y un límite final de 60,000 caracteres — cada descarte indica truncated: true. Los modos en línea rechazan un prefijo "/" simple; output="file" lo acepta. sample_interval diezma eventos a uno por tema por intervalo; change_only omite cambios numéricos en o por debajo del umbral. |
Recibo nt_subscribe predeterminado (sin valores de muestra, unos cientos de caracteres serializados, muy por debajo del presupuesto de 20,000 caracteres):
{
"connected": true,
"output": "file",
"recording_id": "nt-record-2026-09-18T120000Z.ndjson",
"path": "recordings\\nt-record-2026-09-18T120000Z.ndjson",
"duration_seconds": 10.0,
"rows": 214,
"topic_count": 6,
"topics": ["/SmartDashboard/gyro_angle", "/SmartDashboard/left_speed"],
"topics_truncated": false,
"truncated": false
}
topics lista como máximo 50 nombres (topics_truncated: true cuando hay más); rows es el número de eventos escritos y truncated es verdadero cuando el límite de captura max_rows detuvo la grabación antes de tiempo.
| nt_start_subscription | Abre una suscripción persistente. Respuesta: {"connected": bool, "subscription_id": str, "started": bool}. |
| nt_poll_subscription | Lee muestras almacenadas en búfer de una suscripción persistente. Respuesta: {"connected": bool, "samples": {topic: [...]}}. |
| nt_stop_subscription | Detiene una suscripción persistente. Respuesta: {"connected": bool, "stopped": bool}. |
Herramientas de grabación sin conexión
| Herramienta | Descripción |
|---|---|
nt_list_recordings | Lista grabaciones. Cada entrada incluye id, path, size_bytes, modified (flotante Unix) y modified_iso (UTC ISO-8601). |
nt_get_recording_info | Devuelve duración, recuento total de muestras, recuento de temas y metadatos del archivo para una grabación. |
nt_get_history | Devuelve el historial de eventos de un tema. Admite last_seconds, sample_interval y format="summary". La respuesta siempre indica rows (entradas devueltas), total_rows (todos los eventos coincidentes, contados incluso más allá del recorte) y truncated (total_rows > rows, o el límite de 60,000 caracteres descartó filas) para que el recorte nunca sea silencioso. |
nt_list_topics_offline | Lista nombres de temas únicos en una grabación, filtrados por prefix, regex y/o wildcard. |
nt_subscribe_offline | Devuelve eventos para cada tema bajo prefijos. Admite last_seconds, sample_interval y format="summary". limit (predeterminado 1000 por tema) y max_rows (predeterminado 5000 en total) limitan la carga útil; como nt_get_history, la respuesta siempre indica rows / total_rows / truncated. Un prefijo "/" simple se rechaza — redúcelo (por ejemplo, /SmartDashboard/) o usa el CLI nt-recorder para volcar una grabación completa. |
Las herramientas sin conexión leen del directorio establecido por la variable de entorno NT_RECORDINGS_DIR (predeterminado: ./recordings). Las grabaciones son solo locales — el grabador se ejecuta en la laptop de desarrollo y lee NT de la simulación/robot; no se necesitan cambios en el lado del robot.
El CLI nt-recorder también admite --team N para conectar mediante número de equipo; la herramienta MCP nt_connect expone la misma opción mediante team_number.
Desarrollo
- Venv de Python 3.14.0 en
.venv; dependencias instaladas desderequirements.txt(fastmcp==3.4.7,pyntcore==2026.2.2). - Pruebas:
uv run pytest tests/ -v
Notas de versión
0.2.0 — cambios importantes
- Reestructuración de salida de
nt_subscribe: el parámetroformatse eliminó y se reemplazó poroutput, que por defecto es"file". Los llamadores que pasabanformat=deben cambiar aoutput=. En el modo"file", la respuesta es un recibo compacto (ruta de grabación, recuento de filas, lista de temas) sin valores de muestra; los modos en línea ("summary","samples") están limitados porlimit,max_rowsy un límite de 60,000 caracteres. - Las herramientas sin conexión devuelven recibos:
nt_get_historyahora incluyerows/total_rows/truncated;nt_subscribe_offlinedevuelve{recording_id, topics, rows, total_rows, truncated}. El recorte nunca es silencioso. - Guardas de objetivo de
nt_connect: un objetivo ambiguo (tantoteam_numbercomo unserver_ipno predeterminado) se rechaza antes de cualquier cambio de estado, y re-apuntar un cliente en ejecución se rechaza — llama ant_disconnectprimero. nt_connection_infoganótargetyversion:targetes el objetivo de conexión resuelto (nullantes de la primera conexión);versiones la versión del paquete instalado.
Licencia
Este proyecto está bajo la Licencia MIT.