Network Table MCP
Servidor MCP que expõe as NetworkTables (NT4) da FRC para agentes de IA. Lê, escreve e monitora as tabelas de rede de um robô.
Documentação
nt-mcp-server
Um servidor MCP autônomo para ler, escrever e monitorar dados de NetworkTables do FRC. Ele permite que um agente de IA converse com as tabelas de rede de um robô através do protocolo NetworkTables. O alvo principal é a simulação local do RobotPy (python -m robotpy sim em 127.0.0.1:5810).
dependências fixadas (fastmcp==3.4.7, pyntcore==2026.2.2).
Executar o servidor
uv run nt-mcp-server
Ou, de forma equivalente, a partir de um checkout sem o shim do uv:
python -m nt_mcp_server
O servidor roda em stdio, que é como os clientes MCP (como o opencode) conversam com ele.
Conectar à simulação NetworkTables do RobotPy
A simulação deve estar em execução antes que o servidor possa ler ou escrever qualquer coisa útil. Inicie-a a partir do próprio projeto e venv:
cd <path-to-try-robotpy> && .venv\Scripts\activate && python -m robotpy sim
O servidor conecta-se a 127.0.0.1:5810 por padrão, que é onde a simulação escuta.
Conectar à NetworkTables de um Robô Real
Na maioria dos casos, basta gravar a NetworkTables e usar o MCP para analisar as gravações.
Se você quiser conectar-se à NetworkTables de um robô real em tempo real, você precisa ter 2 adaptadores de rede no seu dispositivo: um para Internet e outro para comunicação com o robô. Uma abordagem é usar seu adaptador sem fio para conectar-se ao Wi-Fi e usar um cabo Ethernet para conectar-se ao robô. Alternativamente, você pode obter um Adaptador de Rede USB como segundo adaptador. Em ambos os casos, pode ser necessário configurar o roteamento de rede do seu dispositivo.
Registrar em qualquer agente
O servidor é um pacote executável via uvx a partir do git, então qualquer cliente MCP pode iniciá-lo sem um checkout local ou um venv pré-construído. Execute-o sob demanda:
uvx --from git+https://github.com/Mzzj114/nt-mcp-server.git nt-mcp-server
Ou instale o script de console uma vez e execute-o em qualquer lugar:
uv tool install "git+https://github.com/Mzzj114/nt-mcp-server.git"
uvx nt-mcp-server
Adicione esta entrada à configuração MCP do seu agente (mostrada aqui como o opencode.jsonc de nível de projeto do opencode):
{
"mcp": {
"nt": {
"type": "local",
"command": [
"uvx",
"--from",
"git+https://github.com/Mzzj114/nt-mcp-server.git",
"nt-mcp-server"
],
"enabled": true
}
}
}
Verifique com opencode mcp list a partir da raiz do projeto: o servidor nt deve aparecer como conectado.
Carregar a habilidade nt-mcp-workflow
O repositório inclui uma habilidade de agente em skills/nt-mcp-workflow/ que ensina um agente a conduzir uma investigação de NetworkTables (ao vivo, replay offline e gravação). O opencode não verifica um diretório .agents/skills local do projeto — ele apenas carrega automaticamente ~/.agents/skills, ~/.claude/skills, .opencode/skill(s)/ do projeto e diretórios listados sob skills.paths explícito. Adicione este bloco ao seu opencode.jsonc (mesmo arquivo da entrada mcp acima):
{
"skills": {
"paths": ["../nt-mcp-server/skills"]
}
}
O caminho relativo é resolvido em relação ao diretório que contém o arquivo de configuração, então ajuste-o para onde seu checkout deste repositório estiver em relação a essa configuração. O opencode verifica skills.paths recursivamente em busca de **/SKILL.md, então apontar para o diretório skills do repositório expõe nt-mcp-workflow.
O opencode carrega sua configuração uma vez na inicialização e não faz hot-reload — reinicie o opencode após editar a configuração para que a habilidade apareça.
Gravar NetworkTables em NDJSON (offline)
O CLI nt-recorder conecta-se a um servidor NT4 ao vivo e escreve eventos de valor em um arquivo .ndjson com timestamp. Ele roda no laptop de desenvolvimento e lê NT da simulação ou do robô; nenhuma alteração no lado do robô é necessária.
uv run nt-recorder --prefixes /SmartDashboard/ --output-dir recordings
Ou, sem checkout local, execute-o diretamente do git via uvx (mesma fonte do servidor):
uvx --from git+https://github.com/Mzzj114/nt-mcp-server.git nt-recorder --prefixes /SmartDashboard/ --output-dir recordings
Ou instale a ferramenta uma vez para que tanto nt-mcp-server quanto nt-recorder estejam no PATH, e então execute qualquer um sem re-buscar:
uv tool install "git+https://github.com/Mzzj114/nt-mcp-server.git"
nt-recorder --prefixes /SmartDashboard/ --output-dir recordings
O gravador é um script de console autônomo, independente do servidor MCP — executar o servidor via uvx não o inicia, e o agente não precisa estar conectado para gravar.
Opções:
--prefixes— prefixos de tópicos para assinar (padrão:/)--output-dir— diretório para arquivos de saída (padrão:./recordings)--duration— gravar por N segundos e depois sair (padrão: executar até Ctrl+C)--team— conectar via número da equipe em vez de IP/porta do servidor--server-ip/--server-port— endereço do servidor NT4 (padrão:127.0.0.1:5810)--identity— string de identidade do cliente (padrão:nt-recorder)--quiet— suprimir saída de status para stderr
Os arquivos de saída são nomeados nt-record-<YYYY-MM-DDTHHMMSSZ>.ndjson (sem dois-pontos, seguro para Windows). Cada linha é {"time": float, "topic": str, "value": jsonable}. Códigos de saída: 0 limpo, 1 falha de conexão, 2 erro de disco/E/S.
Execute
uv cache pruneouuv cache clearse você não quiser que arquivos de cache permaneçam no seu dispositivo apósuvx.
Ferramentas
O servidor expõe 18 ferramentas (13 ao vivo + 5 offline). Cada resposta de ferramenta ao vivo inclui um sinalizador connected.
Ferramentas ao vivo
| Ferramenta | Descrição |
|---|---|
nt_connect | Inicia o cliente NT4 e aguarda uma conexão ao vivo. Passe exatamente um alvo: team_number, ou server_ip/server_port com o server_ip padrão. Parâmetros: server_ip="127.0.0.1", server_port=5810, team_number=None, identity="nt-mcp", timeout_seconds=5.0. O sucesso retorna {"connected": true, "status": "connected", "target": {...}} onde target relata o alvo resolvido (ex.: {"kind": "server", "server_ip": "127.0.0.1", "server_port": 5810} ou {"kind": "team", "team_number": 8326, "server_port": 5810}). Duas recusas retornam {"connected": false, "error": ...}: um alvo ambíguo (tanto team_number quanto um server_ip não padrão) é rejeitado antes de qualquer mudança de estado, e redirecionar um cliente em execução é rejeitado — chame nt_disconnect primeiro. Em timeout, a resposta adiciona diagnósticos connections, elapsed_seconds e um hint de roteamento. O caminho team_number resolve endereços de robô via busca por número de equipe do pyntcore; a lista exata de endereços ainda não foi verificada contra hardware real, então o target resolvido é relatado em vez de assumido. |
nt_disconnect | Para o cliente NT4 e encerra assinaturas persistentes. Retorna {"connected": false, "status": "disconnected"}. |
nt_connection_info | Retorna o estado da conexão: {"connected": bool, "connections": [{"remote_id", "remote_ip", "last_update"}], "target": resolved_target | null, "version": str}. target é o alvo de conexão resolvido (null antes da primeira conexão); version é a versão do pacote instalado ("unknown" quando os metadados estão ausentes). |
nt_get | Retorna o valor normalizado em JSON de um tópico. Resposta: {"connected": bool, "value": jsonable | null}. |
nt_get_multiple | Retorna todos os tópicos solicitados. Resposta: {"connected": bool, "values": {topic: value}}. |
nt_get_info | Retorna metadados do tópico. Resposta: {"connected": bool, "info": {name, type_str, properties} | null}. |
nt_set | Publica um valor. Resposta: {"connected": bool, "ok": bool, "warning": str | null}. Adicione strict_type_check=True para recusar incompatibilidades de tipo. |
nt_set_multiple | Escreve cada par {topic: value}. Resposta: {"connected": bool, "results": {...}, "warnings": {...}}. |
nt_list_topics | Lista nomes de tópicos, filtrados por prefix, regex e/ou wildcard. Resposta: {"connected": bool, "topics": [...]}. |
nt_subscribe | Amostra atualizações sob prefixos por duration segundos. Mudança significativa: o parâmetro format foi removido em favor de output, que tem como padrão "file" — a mesma janela é capturada em uma gravação NDJSON (formato nt-recorder, gravada em output_dir ou NT_RECORDINGS_DIR) e a resposta é um recibo compacto sem valores de amostra. Modos inline: output="summary" retorna min/max/média/último por tópico; output="samples" retorna {topic: [{"time", "value"}, ...]} bruto. Ambos os modos inline são limitados por limit (por tópico), max_rows (total, padrão 5000) e um teto final de 60.000 caracteres — cada descarte declara truncated: true. Modos inline recusam um prefixo "/" vazio; output="file" o aceita. sample_interval reduz eventos para um por tópico por intervalo; change_only ignora mudanças numéricas iguais ou abaixo do limite. |
Recibo nt_subscribe padrão (sem valores de amostra, algumas centenas de caracteres serializados, bem abaixo do orçamento 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 no máximo 50 nomes (topics_truncated: true quando existem mais); rows é o número de eventos gravados e truncated é verdadeiro quando o limite de captura max_rows interrompeu a gravação antecipadamente.
| nt_start_subscription | Abre uma assinatura persistente. Resposta: {"connected": bool, "subscription_id": str, "started": bool}. |
| nt_poll_subscription | Lê amostras em buffer de uma assinatura persistente. Resposta: {"connected": bool, "samples": {topic: [...]}}. |
| nt_stop_subscription | Para uma assinatura persistente. Resposta: {"connected": bool, "stopped": bool}. |
Ferramentas de gravação offline
| Ferramenta | Descrição |
|---|---|
nt_list_recordings | Lista gravações. Cada entrada inclui id, path, size_bytes, modified (float Unix) e modified_iso (UTC ISO-8601). |
nt_get_recording_info | Retorna duração, contagem total de amostras, contagem de tópicos e metadados do arquivo para uma gravação. |
nt_get_history | Retorna histórico de eventos para um tópico. Suporta last_seconds, sample_interval e format="summary". A resposta sempre declara rows (entradas retornadas), total_rows (todos os eventos correspondentes, contados mesmo além do recorte) e truncated (total_rows > rows, ou o teto de 60.000 caracteres descartou linhas) para que o recorte nunca seja silencioso. |
nt_list_topics_offline | Lista nomes únicos de tópicos em uma gravação, filtrados por prefix, regex e/ou wildcard. |
nt_subscribe_offline | Retorna eventos para todos os tópicos sob prefixos. Suporta last_seconds, sample_interval e format="summary". limit (padrão 1000 por tópico) e max_rows (padrão 5000 total) limitam o payload; como nt_get_history, a resposta sempre declara rows / total_rows / truncated. Um prefixo "/" vazio é recusado — restrinja-o (ex.: /SmartDashboard/) ou use o CLI nt-recorder para despejar uma gravação inteira. |
As ferramentas offline leem do diretório definido pela variável de ambiente NT_RECORDINGS_DIR (padrão: ./recordings). As gravações são apenas locais — o gravador roda no laptop de desenvolvimento e lê NT da simulação/robô; nenhuma alteração no lado do robô é necessária.
O CLI nt-recorder também suporta --team N para conectar via número da equipe; a ferramenta MCP nt_connect expõe a mesma escolha via team_number.
Desenvolvimento
- Venv Python 3.14.0 em
.venv; dependências instaladas derequirements.txt(fastmcp==3.4.7,pyntcore==2026.2.2). - Testes:
uv run pytest tests/ -v
Notas de versão
0.2.0 — mudanças significativas
- Reformulação da saída
nt_subscribe: o parâmetroformatfoi removido e substituído poroutput, que tem como padrão"file". Chamadores que passaramformat=devem mudar paraoutput=. No modo"file", a resposta é um recibo compacto (caminho da gravação, contagem de linhas, lista de tópicos) sem valores de amostra; modos inline ("summary","samples") são limitados porlimit,max_rowse um teto de 60.000 caracteres. - Ferramentas offline retornam recibos:
nt_get_historyagora incluirows/total_rows/truncated;nt_subscribe_offlineretorna{recording_id, topics, rows, total_rows, truncated}. O recorte nunca é silencioso. - Proteções de alvo
nt_connect: um alvo ambíguo (tantoteam_numberquanto umserver_ipnão padrão) é rejeitado antes de qualquer mudança de estado, e redirecionar um cliente em execução é recusado — chament_disconnectprimeiro. nt_connection_infoganhoutargeteversion:targeté o alvo de conexão resolvido (nullantes da primeira conexão);versioné a versão do pacote instalado.
Licença
Este projeto está sob a Licença MIT.