March 12, 2026

otparse: An MCP Server for OT/ICS PCAP Analysis

Most of the systems I work on every day run BACnet or Modbus. Building automation controllers, variable air volume boxes, chillers talking to a BAS – it’s all networked, and almost none of it was designed with security in mind. That overlap between the physical world and the network is part of what led me toward OT/ICS security.

One thing that comes up constantly in ICS security work is the packet capture. You grab traffic off an industrial network and then you need to figure out what you’re looking at: which devices were communicating, what protocol, what function codes were used. The tools exist, but the workflow of loading a file into Wireshark or running tshark manually and reasoning over the output isn’t fast, especially when you’re also trying to learn the protocols themselves.

This project is a natural extension of the AI-assisted SOC triage lab I wrote about last week. That lab used an MCP server called netparse to give Claude Code access to tshark for general network analysis. otparse applies the same pattern to OT protocols specifically.

The full source and setup instructions are in the repository.


What It Does

otparse is a containerized MCP server. It exposes two tools:

You point either tool at a PCAP file inside the container, and it hands back structured JSON. Function codes, unit IDs, object types, service names, invoke IDs – the fields that matter for understanding what was happening on the network. Claude can then reason over that output directly.

The design is the same as netparse: tshark does the protocol dissection, the MCP server normalizes the output, and the model handles the interpretation. The value of keeping those responsibilities separate is that the analysis stays grounded in what the tools actually found rather than what the model guesses.


Container Design

The container runs with no outbound network access and a read-only /evidence mount. For anything touching forensic data, those felt like non-negotiable constraints. The evidence can’t be modified, and the container can’t reach out over the network even if something in a malicious capture tries to redirect it.

It also runs as a non-root user, which is straightforward to set up in Docker and removes another category of potential problems.


What Came Out of Building It

The most useful early lesson was about tshark attribute consistency. Pyshark exposes protocol fields as object attributes, but the attribute names tshark uses for the same conceptual field aren’t always consistent across dissector versions or capture types. Both parsers handle this by walking a list of candidate attribute names and returning the first one that exists, which made the results noticeably more reliable across different captures.

The other thing worth noting: Modbus direction detection (whether a frame is a request or a response) depends on pyshark exposing the right flags from the dissector. In practice this doesn’t always happen cleanly, and a lot of frames will come back with "direction": "unknown". That’s something to improve in a future pass.


Where This Is Going

v0.1.0 covers Modbus and BACnet because those are the two protocols I see most in the field. The next version adds broader ICS protocol coverage: EtherNet/IP, S7comm, DNP3, IEC 60870-5-104, OPC-UA, IEC 61850, and PROFINET. That pass is already in progress.

After that, the plan is anomaly heuristics – unusual function codes, write-heavy sessions, broadcast storms, that kind of thing – and eventually a timeline summarizer that can give a higher-level picture of what a capture contains before diving into individual frames.


Repository: https://github.com/desvert/otparse-mcp