Network Table MCP

FRC NetworkTables (NT4) protokolünü yapay zeka ajanlarına sunan MCP sunucusu. Bir robotun ağ tablolarını okur, yazar ve izler.

Dokümantasyon

nt-mcp-server

What is a MCP?

The Model Context Protocol (MCP) is a standard way for AI agents to use external tools and data. The concept is established by Anthropic researchers in the end of 2024. For more information, see https://modelcontextprotocol.io/.

This server exposes FIRST Robotics Competition (FRC) NetworkTables through MCP, so a coding agent can inspect telemetry, diagnose robot behavior, and test values without manually copying data between the robot, dashboards, and code.

It works with a local RobotPy simulation by default and can also connect to a real robot.

How do I use AI while connecting to the Robot Wifi?

Obviously Robot Wifi doesn't provide Internet access, so you can't call LLM. The key is to use TWO network adapters: one for the Robot Wifi, another for Internet access. The first network adapter is usually the one inside your device that you always use to go online. For the second one, your laptop may have a Ethernet port, you can therefore connect a Ethernet cable to the DS port of the robot radio. In other cases, you may want a USB-to-Ethernet adapter or a USB wireless network adapter. The connections should be ready to go now. Rarely you need to configure the routing table of your device to explicitly guide traffic targeting the robot IP to the correct network adapter.

Register with an agent

The package can run directly from Git with uvx, so no checkout or pre-built virtual environment is required. Install uv first, then use the setup for your agent.

Codex

codex mcp add nt -- uvx --from git+https://github.com/Mzzj114/nt-mcp-server.git nt-mcp-server
codex mcp list

Claude Code

claude mcp add --scope project nt -- uvx --from git+https://github.com/Mzzj114/nt-mcp-server.git nt-mcp-server
claude mcp list

OpenCode

Add the server to the project's opencode.jsonc:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "nt": {
      "type": "local",
      "command": [
        "uvx",
        "--from",
        "git+https://github.com/Mzzj114/nt-mcp-server.git",
        "nt-mcp-server"
      ],
      "enabled": true
    }
  }
}

Verify the connection with opencode mcp list.

Tools

The server exposes 16 tools (13 live + 3 offline). Every live response includes a connected flag. Reads and writes have separate tools.

Live tools

ToolDescription
nt_connectStart the NT4 client and wait for a connection. Defaults to 127.0.0.1:5810; choose team_number or server_ip/server_port. Conflicting targets and re-targeting a running client are refused; disconnect first. Returns the resolved target or timeout diagnostics.
nt_disconnectStop the client, tear down persistent subscriptions and request active recordings to close.
nt_connection_infoReturn connection state, remote peers, resolved target and package version.
nt_read_topicsRead one or more exact topics. Returns {connected, values: {topic: value}}; unknown topics have null values.
nt_get_topic_infoReturn one topic's name, NT type and properties, or null if unknown.
nt_write_topicsPublish an updates map, including a single-entry map. Returns per-topic results and warnings. strict_type_check=True refuses known type mismatches. Writes are not atomic.
nt_list_topicsDiscover live topic names with optional prefix, regex and wildcard filters.
nt_sampleObserve selected updates for duration seconds (up to 60). Defaults to output="summary"; output="samples" returns timestamp/value rows. Returns samples keyed by topic, rows, total_rows and truncated.
nt_start_subscriptionStart a persistent in-memory subscription and return its subscription_id. buffer_size bounds retained events; oldest events are discarded when full.
nt_poll_subscriptionRead buffered events; clear=True clears them after polling.
nt_stop_subscriptionStop the subscription and free its resources.
nt_start_recordingStart an NDJSON recording and immediately return its recording_id and path for a human-controlled test window.
nt_stop_recordingClose a recording and return a compact receipt with timing, row count, topic names and truncation flags, without sample values.

Live sampling, subscriptions, recordings and recording queries share prefixes, exact topics, regex and wildcard selectors. Entries within a list are ORed; different selector kinds are ANDed. At least one selector is required. A bare prefixes=["/"] is allowed for recordings, but refused for inline sampling and recording queries unless another selector narrows it.

nt_sample blocks for its fixed window and returns inline results. For an interactive test, call nt_start_recording, perform the test, then call nt_stop_recording. Use the returned ID for offline analysis after the file closes.

Offline recording tools

ToolDescription
nt_list_recordingsList available files, newest first, with file metadata and persisted capture timing when available.
nt_get_recording_infoReturn capture duration, NT event span, sample count, file metadata and a sorted topic list. prefix, regex and wildcard filter topic discovery; topic_limit defaults to 100 (maximum 1000). topic_count describes the whole file; matching_topic_count, topics_returned and topics_truncated describe discovery.
nt_query_recordingQuery selected topics. Returns {recording_id, topics, rows, total_rows, truncated}. Defaults to output="samples"; output="summary" returns statistics under the same topics key. Supports start (inclusive), end (exclusive), last_seconds and sample_interval.

The offline directory defaults to NT_RECORDINGS_DIR or ./recordings; output_dir overrides it. Omitting recording_id selects the most recently modified recording. Queries return the resolved ID. The MCP tools refuse to inspect a recording still being written by this server; a separate CLI recorder must also be stopped before analysis.

For one topic's history:

nt_query_recording(
    topics=["/SmartDashboard/Swerve/Pose X"],
    recording_id="nt-record-...ndjson",
    last_seconds=5,
    output="summary",
)

Inline sampling and offline queries are bounded by per-topic limit, total max_rows (default 5000, maximum 5000) and a 60,000-character ceiling. Summary statistics describe retained rows; rows / total_rows / truncated report reduction explicitly. Offline total_rows counts matching events before limits and decimation; live total_rows counts events after sampling/change filters and before output clipping. last_seconds uses the latest NT event timestamp, which can differ from the capture clock.

Each new recording has a sibling .meta.json sidecar. capture_duration_seconds measures capture time; event_span_seconds measures the range of NT last-change timestamps, including older immediate values. Legacy files without sidecars report duration_source="event_span".

The nt-recorder CLI remains available independently of MCP, including --team N for robot address lookup. Recordings are local to the server host; no robot-side changes are needed.

Development

  • Python 3.14.0 venv in .venv; deps installed from requirements.txt (fastmcp==3.4.7, pyntcore==2026.2.2).
  • Tests: uv run pytest tests/ -v

To run the mcp server by yourself from a local checkout, start the stdio MCP server with:

uv run nt-mcp-server

Equivalent Python entry point:

python -m nt_mcp_server

For RobotPy simulation, start the simulator from the robot project:

python -m robotpy sim

Then use nt_connect with its defaults to connect to 127.0.0.1:5810.

For a real robot, connect the development machine to the robot network and call nt_connect with team_number. If the agent also needs Internet access, use separate network adapters—for example, Wi-Fi for Internet and Ethernet or a USB network adapter for the robot—and configure routing if needed.

Release notes

0.3.0 — consolidated tool surface

The exposed MCP surface changes from 20 to 16 tools. Restart the MCP server/client to refresh tool discovery. These are breaking name and argument changes:

Previous callReplacement
nt_get(topic) / nt_get_multiple(topics)nt_read_topics(topics=[...]); values are always keyed by topic
nt_set(topic, value) / nt_set_multiple(updates)nt_write_topics(updates={topic: value}); results/warnings are always keyed by topic
nt_get_info(topic)nt_get_topic_info(topic)
nt_subscribe(output="summary") or output="samples"nt_sample(output=...); defaults to summary and has no file mode
nt_subscribe(output="file")nt_start_recording(...), then nt_stop_recording(recording_id)
nt_get_history(topic, ...)nt_query_recording(topics=[topic], ...); read topics[topic]
nt_subscribe_offline(format=...)nt_query_recording(output=...)
nt_list_topics_offline(...)nt_get_recording_info(...); read topics and discovery counts

Schemas describe every parameter and enforce output enums, absolute topic names, non-empty batches, positive sampling intervals, row budgets, port ranges and filename-only recording IDs. Offline reader functions in nt_recorder retain their Python API.

0.2.0 — breaking changes

  • nt_subscribe output rework: the format parameter was removed and replaced by output, which defaults to "file". Callers that passed format= must switch to output=. In "file" mode the response is a compact receipt (recording path, row count, topic list) with no sample values; inline modes ("summary", "samples") are bounded by limit, max_rows, and a 60,000-character ceiling.
  • Offline tools return receipts: nt_get_history now includes rows / total_rows / truncated; nt_subscribe_offline returns {recording_id, topics, rows, total_rows, truncated}. Clipping is never silent.
  • nt_connect target guards: an ambiguous target (both team_number and a non-default server_ip) is rejected before any state change, and re-targeting a running client is refused — call nt_disconnect first.
  • nt_connection_info gained target and version: target is the resolved connect target (null before the first connect); version is the installed package version.

License

This project is under MIT License.