Raw MC protocol vs McpX vs MX Component, side by side in C#
The same task — reading D100–D102 from a Mitsubishi Electric PLC — written three ways: building MC protocol messages by hand, the .NET library McpX, and Mitsubishi Electric's MX Component. Compare code size, setup, supported environments and where each fits.
Updated
There are three broad ways to read and write a Mitsubishi Electric PLC from C#: build the MC protocol messages yourself, use a library such as McpX, or use Mitsubishi Electric’s MX Component.
This article writes the same task all three ways: “read the three words D100–D102 from a PLC connected over Ethernet.” Seeing them side by side makes it clear what each one handles for you and what it leaves to you.
1. Writing the MC protocol directly
Using nothing but .NET’s TcpClient, turn the message from the 3E frame article into bytes. The device code for D is A8, and the point count is 3.
using System.Buffers.Binary;
using System.Net.Sockets;
using var client = new TcpClient();
client.Connect("192.168.3.39", 5000);
using var stream = client.GetStream();
// 3E frame, binary: batch read 3 words from D100 (0401)
byte[] request =
[
0x50, 0x00, // Subheader
0x00, 0xFF, 0xFF, 0x03, 0x00, // Destination (own station)
0x0C, 0x00, // Request data length = 12
0x10, 0x00, // Monitoring timer = 4 s
0x01, 0x04, 0x00, 0x00, // Command 0401 / subcommand 0000
0x64, 0x00, 0x00, // Head device number = 100
0xA8, // Device code = D
0x03, 0x00, // Points = 3
];
stream.Write(request);
// Read the first 9 bytes of the response (subheader to response data length)
byte[] header = new byte[9];
stream.ReadExactly(header);
if (header[0] != 0xD0 || header[1] != 0x00)
throw new InvalidDataException("Not a 3E frame response");
int length = BinaryPrimitives.ReadUInt16LittleEndian(header.AsSpan(7));
// Read the rest (end code + data)
byte[] body = new byte[length];
stream.ReadExactly(body);
ushort endCode = BinaryPrimitives.ReadUInt16LittleEndian(body);
if (endCode != 0)
throw new Exception($"The PLC returned an error: {endCode:X4}");
short[] values = new short[3];
for (int i = 0; i < values.Length; i++)
values[i] = BinaryPrimitives.ReadInt16LittleEndian(body.AsSpan(2 + i * 2));It works, but it only covers “read D as three words in binary.” To use it for real, you end up adding things like:
- Splitting requests when reading more than 960 words
- Assembling values that span two words, such as
intandfloat - Handling bit devices like M, and hex-numbered devices like X and Y
- Timeouts when no response comes back, and re-establishing the connection afterwards
- iQ-R subcommands and remote password support
This is the best way to understand what is inside the messages. But to build it into an application, you have to write and test all of the above yourself.
2. Using McpX
Add McpX from NuGet and write the same task.
using McpXLib;
using McpXLib.Enums;
using var mcpx = new McpX("192.168.3.39", 5000);
short[] values = mcpx.BatchRead<short>(Prefix.D, "100", 3);The single BatchRead<short> line takes over both building the message and parsing the response from section 1. Change the type to int or float and McpX also works out the word count and assembles the values. Reads beyond 960 words are split automatically.
When the PLC returns an error, McpX throws McProtocolException, and the ErrorCode property gives you the code.
McpX is written purely in .NET, so it runs on Linux and macOS as well as Windows. In exchange, it supports Ethernet (TCP / UDP) and GX Simulator3 only — no USB or serial connections.
3. Using MX Component
MX Component is Mitsubishi Electric’s communication library. Here we use the 64-bit edition of Version 5, following the manual. You need two things first:
- Install MX Component and configure the connection in its Communication Setup Utility. Each configuration gets a number called the logical station number
- In Visual Studio, use Add Reference to add the COM “ActUtlType64 Control” to your project
using ActUtlType64Lib;
var plc = new ActUtlType64Class();
plc.ActLogicalStationNumber = 1; // Logical station number from the Communication Setup Utility
int ret = plc.Open();
if (ret != 0)
throw new Exception($"Failed to connect: {ret:X8}");
try
{
short[] values = new short[3];
ret = plc.ReadDeviceBlock2("D100", values.Length, out values[0]);
if (ret != 0)
throw new Exception($"Failed to read: {ret:X8}");
}
finally
{
plc.Close();
}No IP address or port appears in the code. The connection details live in the Communication Setup Utility, and the code only refers to them by logical station number.
ReadDeviceBlock2 takes the device name as a string such as "D100" and reads values in 2-byte (short) units. The caller must allocate an array at least as large as the point count; the manual warns that too small an area can cause serious problems such as an application error. Errors come back as return values, not exceptions, so check for zero after every call.
MX Component’s strength is the number of connection routes. Besides Ethernet, the same code can connect over:
- USB and serial
- Network boards such as MELSECNET/H and CC-Link IE
- Simulators such as GX Simulator2 / 3
On the other hand, it runs only on Windows, and it is a product you need to purchase.
The three side by side
| Raw MC protocol | McpX | MX Component | |
|---|---|---|---|
| What you add | Nothing (.NET only) | NuGet package McpX | MX Component install and a COM reference |
| Where the target is set | IP and port in code | IP and port in the constructor | Communication Setup Utility + logical station number |
| OS | Anywhere .NET runs | Windows, Linux, macOS | Windows |
| Routes | Whatever you implement (Ethernet) | Ethernet (TCP / UDP), GX Simulator3 | Ethernet, USB, serial, network boards, simulators and more |
| Value types | Convert from bytes yourself | Choose bool, short, int, float and more by type | ReadDeviceBlock2 returns short; assemble int and others yourself |
| Errors | Check the end code yourself | Exception (McProtocolException) | Check the return value every call |
| Points per call | Split yourself past the limit (960 words for batch read) | Split automatically past the limit | Any count within the device’s range |
| License | — | MIT (free, commercial use OK) | Paid |
Which one to choose
Three questions decide it. Answer them from the top and you will usually land on one.
1. Do you connect over something other than Ethernet?
If the PLC is connected over USB, serial, or a network board such as MELSECNET/H or CC-Link IE, choose MX Component. Both McpX and hand-written code talk over Ethernet only.
2. Do you run on something other than Windows?
If you connect over Ethernet, look at where the program runs next. For a Linux server, a Docker container, a Raspberry Pi or a macOS development machine, choose McpX. MX Component runs only on Windows.
3. How will you distribute it, and under what license?
On Windows over Ethernet, both McpX and MX Component will do the job. The deciding factor is how the application is distributed.
- McpX fits applications you ship to many PCs or to other companies. It is MIT-licensed and free, and it goes into your application as a NuGet reference, so there is nothing to install or configure on each PC that runs it
- MX Component fits applications that run on fixed in-house PCs where connections are already managed with MX Component. You can change the connection target in the Communication Setup Utility without touching the code
Common scenarios
| Scenario | Choose |
|---|---|
| Collect factory operating data on a Linux server and show it on a web dashboard | McpX |
| Run a gateway that sends PLC data to the cloud in Docker | McpX |
| Operate a USB-connected PLC from a Windows inspection application | MX Component |
| Monitor several PLCs from a PC fitted with a CC-Link IE board | MX Component |
| Talk to a PLC from a language other than C#, or from a microcontroller | Hand-written (the message knowledge in this guide) |
Knowing the messages pays off whichever you choose
You will rarely build a real system from raw messages. But knowing their structure lets you trace problems even when you use a library: you can tell what each byte means when you inspect traffic in Wireshark, and what the error code the PLC returned points to. The 3E frame and error code articles give you exactly that.
Sources
- MX Component Version 5 Reference Manual (Japanese edition, SH-082394) pp.29, 48–49, 56–57, 473–478, 647
- MELSEC Communication Protocol Reference Manual (Japanese edition, SH-080003) pp.41–44, Appendix 7 p.473
- SLMP Reference Manual (Japanese edition, SH-080931) pp.34–38