mcpField
M
Modbus TCP/RTU Device

Modbus TCP/RTU Device

ローカル
github.com科学・教育235 週間前に更新

Modbus TCP/RTU Device について

Modbus TCP/RTU Deviceは、イーサネットまたはシリアル経由でModbus機器を読み取り・制御するMCPサーバーです。機器制御向けに、YAMLまたはJSONのレジスターマップで型や単位、書き込み制限を設定できます。テストはシミュレーション環境で行われています。

主な機能

  1. 01Modbus TCP・RTU・ASCII対応
  2. 02レジスターマップによる型付きポイント
  3. 03ポイントごとの書き込み制限
  4. 04書き込み後の読み戻し検証
  5. 05監査ログと読み取り専用モード
  6. 06マップ定義の安全状態を適用

活用シーン

  1. 01温度コントローラーの工学単位の値を読む
  2. 02設定範囲内でコントローラーの設定値を変更
  3. 03シリアルまたはTCPのModbus接続を診断
  4. 04マップで定義された安全状態を機器に要求

MCP 対応

Modbusの接続情報やポイント・レジスター操作のツールをAIエージェントに提供するMCPサーバーです。クライアントはレジスターマップやコマンドログを確認し、マップに定義があれば安全状態を適用できます。

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

mcp.json · 共通設定
{
"mcpServers": {
"k-dense-ai-labmcp-modbus": {
"command": "uvx",
"args": [
"labmcp-modbus"
],
"env": {
"LABMCP_ADDRESS": "<LABMCP_ADDRESS>",
"LABMCP_SIMULATE": "<LABMCP_SIMULATE>",
"LABMCP_READ_ONLY": "<LABMCP_READ_ONLY>",
"LABMCP_LIMITS": "<LABMCP_LIMITS>"
}
}
}
}
起動コマンドuvx labmcp-modbus
設定が必要な環境変数
LABMCP_ADDRESSInstrument address, e.g. serial:///dev/ttyUSB0 or tcp://192.168.1.50:5025
LABMCP_SIMULATESet to 1 to use the built-in simulator (no hardware)
LABMCP_READ_ONLYSet to 1 to disable all state-changing tools
LABMCP_LIMITSSafety limit overrides, e.g. max_temperature_c=80

ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。

パッケージ
pypilabmcp-modbus0.1.3

ツール

12

掲載時のツール一覧 · 2 週間前に更新

このツールにパラメーターはありません。

詳細

Modbus TCP/RTU デバイス — MCP サーバー

AI エージェントが、Ethernet(Modbus TCP)または RS-485/RS-232(Modbus RTU/ASCII)経由で Modbus デバイスを読み取り、制御できるようにします。対象は、PID 温度コントローラー、循環チラー、PLC、プロセスセンサー、VFD、データロガーなどです。デバイスは レジスターマップ(YAML または JSON)で一度定義します。すると、エージェントは生のレジスターではなく、process_temperature = 37.2 °C や setpoint のような、実単位を持つ名前付きポイントを操作できます。サーバーはマップのルールを適用します。名前を指定して書き込めるのは writable ポイントだけで、書き込み可能な数値にはすべて min と max が必要です。また、範囲外の値は送信前に拒否されます。マップでは 安全状態も定義できます。これは、SAFETY ツールが要求に応じて実行するポイント書き込みのリスト(ヒーターをオフにする、コントローラーをスタンバイにするなど)です。

パッケージlabmcp-modbus
計測機器あらゆる Modbus デバイス:温度コントローラー(Watlow、Eurotherm、Omega、Autonics など)、チラーおよび循環装置、PLC およびリモート I/O、センサー/トランスミッター、VFD、電力計、データロガー
インターフェースEthernet(Modbus TCP、ポート 502)、RS-485 / RS-232(Modbus RTU または ASCII)、シリアル-Ethernet ゲートウェイ(TCP 経由の RTU)
プロトコルMODBUS Application Protocol Specification V1.1b3、MODBUS over Serial Line V1.02、MODBUS Messaging on TCP/IP Implementation Guide V1.0b;クライアントは pymodbus 3.8+ 経由
ステータス🧪 シミュレーション済み:メモリー内のシミュレーションコントローラーとローカルの pymodbus サーバーでテスト済みです。ハードウェアではまだ検証されていません。ハードウェアテストを報告

通常のレジスター操作だけを行う Modbus MCP と比べて、このサーバーには次の機能があります。

  • 型付きレジスターマップ: int16/uint16/int32/uint32/float32/float64/bool、ワード順とバイト順、scale と offset、単位、列挙値(0 = standby, 1 = auto)、説明に対応します。
  • ポイントごとの制限: 書き込み可能なポイントには min/max または列挙値が必要で、送信前に値がチェックされます。マップ済みポイントに属するアドレスへの生の書き込みは拒否されるため、制限を回避できません。
  • 読み戻し: write_point はすべて値を読み戻し、一致するかどうかを報告します。
  • 安全状態: マップで定義され、--read-only モードでも動作する apply_safe_state SAFETY ツール。
  • 読み取り専用モード(--read-only)、すべてのリクエストと応答の監査ログ、および上限付きのリクエストサイズ。

ハードウェアなしで試す

uvx labmcp-modbus --simulate --check

シミュレーターは、単一ループの汎用 PID 温度コントローラーです。その構成は、同梱されているレジスターマップの例に記載されています。これは説明用であり、特定のメーカーのマップを複製したものではありません。ヒーター(最大出力時に 3 °C/s)が熱容量を加熱し、熱容量は 22 °C の室温に向けて冷却されます(τ = 90 s)。PID ループには、ランプ動作する作業用設定値とアラームビットがあります。シミュレーターは、実装されていないアドレスには例外 02、独自の範囲外の値(500 °C の設定値など)には 03、誤ったユニット ID には 0B を返します。--simulate --option register_map=my_map.yaml を指定すると、サンプルのレイアウトに含まれないポイントにはゼロで初期化されたストレージが割り当てられるため、独自のマップをテストできます。

デバイスを接続する

  1. デバイスの設定: デバイスの通信メニューで Modbus を有効にし、設定を控えます。
    • RTU(RS-485): ユニット(スレーブ)アドレス(1–247)、ボーレート、パリティ、ストップビットを設定します。サーバーのデフォルトは、Modbus シリアルのデフォルトである 19200 baud、8 データビット、偶数パリティ、1 ストップビットです。多くのデバイスは別の設定(例:9600 8N1)で出荷されます。その場合は、アドレスにデバイスの設定を指定してください。USB-RS485 アダプターの A/B(D−/D+)ラインをデバイスに接続します。A/B の表記はメーカーによって異なるため、応答がない場合は入れ替えてください。信号グラウンドを接続し、長いバスでは両端に 120 Ω の終端抵抗を取り付けます。
    • TCP: IP アドレスを設定します。変更していない場合、ポートは 502 です。多くの TCP デバイスはユニット ID を無視します。お使いのデバイスが無視しない場合、通常は 1 です。TCP 実装ガイドでは、直接アドレス指定するデバイスに 255 を推奨しています。
  2. デバイスの Modbus マニュアルをもとに、レジスターマップを作成します。 例をコピーし、以下のレジスターマップを確認してください。
  3. 接続をテストします:
    uvx labmcp-modbus --address tcp://192.168.1.20:502 --option register_map=~/maps/oven.yaml --check
    uvx labmcp-modbus --address "serial:///dev/ttyUSB0?baudrate=9600&parity=N" --option unit_id=3 \
        --option register_map=~/maps/controller.yaml --check
    uvx labmcp-modbus --address "serial://COM4?baudrate=19200&parity=E" --option register_map=C:/maps/chiller.json --check
    uvx labmcp-modbus --address "tcp://192.168.1.30:4001?framer=rtu" --check      # RTU through a transparent gateway
    
    --check は接続し、マップの最初のポイントをプローブとして読み取って、probe: ok: … またはエラーを表示します。その他のアドレスパラメーター:stopbits=2、bytesize=7、framer=ascii(Modbus ASCII)、timeout=1、retries=2。

レジスターマップ

device:                 # optional
  name: Incubator oven
  manufacturer: Example
  model: X-100
  unit_id: 1            # --option unit_id overrides it
  word_order: big       # default for 32/64-bit points
  byte_order: big

points:
  chamber_temperature:
    table: input        # holding | input | coil | discrete
    address: 0          # 0-based protocol address ("30001" in the manual -> input 0)
    type: int16         # uint16 | int16 | uint32 | int32 | float32 | float64 | bool
    scale: 0.1          # value = raw * scale + offset
    unit: °C
    description: Chamber temperature
  setpoint:
    table: holding
    address: 0          # "40001" -> holding 0
    type: int16
    scale: 0.1
    unit: °C
    writable: true
    min: 20             # required for writable numbers: checked before sending
    max: 60
  mode:
    table: holding
    address: 1
    writable: true
    enum: {0: standby, 1: run}
  heater_enable:
    table: coil
    address: 0
    writable: true

safe_state:             # optional: run in order by apply_safe_state
  - {point: heater_enable, value: false}
  - {point: mode, value: standby}
フィールドデフォルト意味
table(必須)holding(FC03/06/16)、input(FC04、読み取り専用)、coil(FC01/05)、discrete(FC02、読み取り専用)
address(必須)0 始まりのプロトコル(PDU)アドレス。マニュアルの番号:4xxxx → holding xxxx − 1、3xxxx → input、1xxxx → discrete、0xxxx → coil
typeuint16(コイル/discrete は bool)32 ビット型は 2 レジスター、float64 は 4 レジスターを使用します。レジスター内の bool は、0 が false、それ以外は true を意味します
word_order / byte_orderbig / bigbig/big = ABCD(最上位レジスターが先)。little/big = CDAB(PLC で一般的)。big/little = BADC。little/little = DCBA
scale、offset1、0工学値 = raw × scale + offset。書き込み時はレジスターの分解能に合わせて丸めた後、再チェックされます
unit、description""エージェントに表示されます
writablefalseholding レジスターとコイルのみ書き込み可能にできます
min、maxなし工学単位での制限。enum を使用する場合を除き、数値ポイントを書き込み可能にするには必須です
enumなし整数ポイントに対する {number: label}。書き込みではラベルまたは数値を指定できます

サーバーは起動時にマップを検証します。不明なフィールド(例:スペルミスのある maximum)や重複キー(2 つ目の max、または同じポイントの重複定義)は、黙って無視されずエラーになります。そのため、タイプミスによって制限が削除されることはありません。2 つの書き込み可能なポイントが同じレジスターを共有することはできません(片方への書き込みで、もう片方の制限を回避できてしまうためです)。書き込み可能なレジスターを読み取り専用で参照することは問題ありません。マップが無効な場合、list_points にエラーが表示され、デバイスツールは実行を拒否します。サーバーは安全側に倒して動作を停止します。

MCP クライアントに追加する

Claude Code

claude mcp add oven -- uvx labmcp-modbus --address tcp://192.168.1.20:502 --option register_map=/home/me/maps/oven.yaml

Claude Desktop / Cursor / Windsurf(claude_desktop_config.json、.cursor/mcp.json、…)

{
  "mcpServers": {
    "controller": {
      "command": "uvx",
      "args": [
        "labmcp-modbus", "--address", "serial:///dev/ttyUSB0?baudrate=9600&parity=N",
        "--option", "unit_id=1",
        "--option", "register_map=/home/me/maps/controller.yaml",
        "--option", "raw_writes=false"
      ]
    }
  }
}

便利なフラグ:

  • --read-only は読み取りのみを許可します。apply_safe_state は引き続き利用できます。
  • --option raw_writes=false は write_register、write_registers、write_coil を削除するため、エージェントはマップで許可された内容のみを書き込めます。マップが完成したら、この設定を推奨します。

ツール

ツール種類説明
apply_safe_state🛑 安全レジスターマップで定義された安全状態(例:ヒーター出力をオフにする、コントローラーをスタンバイにする)にデバイスを移行し、各手順を順番に書き込んで読み戻します。前の手順が失敗しても、すべての手順を試みます。異常が見られた場合は、直ちに呼び出してください。all_ok が true になるのは、すべての手順が要求された値で書き込まれ、読み戻された場合のみです。デバイスが書き込みを受け付けても無視した場合(例:ローカルモード)は、正常とはみなされません。
get_command_log👁 読み取り装置に送信したコマンドと装置から受信した応答のうち、最新のものを返します(末尾が最新)。デバッグや実行内容の記録に便利です。
get_connection_info👁 読み取り接続中の装置(識別情報、アドレス、シミュレーションまたは実機)、サーバーが読み取り専用かどうか、および有効な安全制限を報告します。最初に呼び出してください。
list_points👁 読み取り読み込まれたレジスターマップを説明します。デバイス、名前付きポイント(テーブル、0 始まりのアドレス、型、スケーリング、単位、書き込み可能かどうか、最小値/最大値、列挙値)、および安全状態への移行手順が含まれます。接続がなくても動作します。
read_coils👁 読み取りコイル(FC01)を読み取ります。運転/停止やリレー状態など、単一ビットの出力が対象です。
read_discrete_inputs👁 読み取りディスクリート入力(FC02)を読み取ります。アラームやリミットスイッチなど、読み取り専用の単一ビット状態が対象です。
read_points👁 読み取りレジスターマップから名前付きポイントを読み取り、デコードして工学単位にスケーリングします(例:process_temperature = 25.1 °C)。読み取れないポイントには error が設定され、呼び出し全体は失敗しません。
read_registers👁 読み取り保持レジスターまたは入力レジスターを、生の符号なし 16 ビット値として読み取ります。必要に応じて int16、32 ビット、または 64 ビット値としてデコードできます。デバイスの調査に使用します。レジスターマップに記載がある場合は、read_points を優先してください。
reconnect🛑 安全装置との接続を閉じて再度開きます(例:装置の電源を入れ直した後や、ケーブルを再接続した後)。
write_coil⚠️ 危険生のコイルを 1 つ切り替えます(FC05)。コイルは機器(ヒーター、ポンプ、モーターなど)の起動や停止を行うことが多いため、マッピング済みのコイルはここでは書き込みできません(write_point を使用してください)。
write_point⚠️ 危険レジスターマップから名前付きポイント(設定値、モード、出力の有効化など)を書き込みます。送信前に、ポイントの書き込み可能フラグ、最小値/最大値、または列挙値に対して値を検証し、生レジスターに変換してから書き込み、読み戻します。設定値や出力を変更すると、実機に作用します。書き込みに成功しても読み戻しに失敗した場合は、read_back_error に理由が示されます。
write_register⚠️ 危険生の保持レジスターを 1 つ書き込みます(FC06)。スケーリングや制限は適用されないため、レジスターマップに記載のないアドレスにのみ使用してください(マッピング済みのアドレスへの書き込みは拒否されます。write_point を使用してください)。レジスターが読み取り可能な場合は、読み戻し結果を返します。
write_registers⚠️ 危険連続する生の保持レジスターを書き込みます(FC16)。例:32 ビット値の上位と下位の両方。スケーリングや制限は適用されず、マッピング済みのアドレスへの書き込みは拒否されます(write_point を使用してください)。

get_connection_info、get_command_log、reconnect は、すべての LabMCP サーバーに組み込まれています。apply_safe_state は、レジスターマップで safe_state が定義されている場合にのみ表示されます。

安全制限

このサーバーにはグローバルな --limit 値はありません。汎用の Modbus クライアントでは、レジスターの意味を判断できないためです。保護機能は、レジスターマップとサーバーによって実現されています。

保護機能場所
writable: false(デフォルト)write_point はそのポイントへの書き込みを拒否します
ポイントごとの min / max / enumwrite_point は範囲外の値を送信前に拒否し、レジスターの分解能(整数または float32)に丸めた後にも再度拒否します
マッピング済みアドレスの保護write_register(s) / write_coil は、マッピング済みポイントと重複するアドレスへの書き込みを拒否します
--option raw_writes=false生の書き込みツールをすべて削除します
--read-onlyすべての書き込みツールを削除します。apply_safe_state は引き続き使用できます
マップ内の safe_stateapply_safe_state は各ステップを順に書き込み、読み戻します。いずれかのステップが失敗しても、すべてのステップを試行します。読み戻した値が一致する場合のみ、そのステップは ok となります。そのため、書き込みを受け付けても無視するデバイス(ローカル/キーパッドモード)は、信頼されるのではなく、その状態が報告されます
リクエストの上限仕様に従い、リクエストあたり 1~125 レジスター(FC03/04)、1~2000 ビット(FC01/02)、1~123 レジスター(FC16)です
ブロードキャストなしシリアル回線ではユニット ID 0 を拒否します。すべてのデバイスに書き込まれるうえ、デバイスはブロードキャストに応答しないためです

プロンプトの例

  • 「現在のチャンバー温度と出力電力は?単位とともにすべてのポイントを表示してください。」
  • 「コントローラーを 2 °C/min で 55 °C まで上昇させ、自動モードに切り替え、ヒーターを有効にして、設定値との差が 0.5 °C 以内になったら知らせてください。」
  • 「上限アラームを 70 °C に設定してから、アラームまたはセンサー障害のビットが有効になっていないか確認してください。」
  • 「保持レジスター 100~109 を読み取り、float32 としてデコードしてください(両方のワード順序を試してください)。新しいチラーをマッピングしています。」
  • 「問題が発生しています。コントローラーを安全状態にして、ヒーターがオフになっていることを確認してください。」

注意事項

  • アドレスは通信上では 0 始まりです。 マニュアルでは、1 始まりの「Modicon」番号(40001 = 保持レジスター 0)がよく使われます。すべての読み取り結果がレジスター 1 つ分ずれている場合、マップで異なる規約が使われています。
  • ワード順序は標準化されていません。 32 ビット値について、Modbus 仕様で定義されているのはレジスター内のバイト順序のみです。float または 32 ビット値が不自然に見える場合は、word_order: little を試してください。decode_as を指定した read_registers を使うと、正しい順序を見つけやすくなります。
  • NaN または無限大を返す float ポイント(多くのデバイスは、センサー障害などで「値なし」を示すために NaN を使用します)は、value: null と error を返します。decode_as を指定した read_registers では、"nan"/"inf" として表示されます。
  • write_point は、単一レジスターポイントには FC06、複数レジスターポイントには FC16、コイルには FC05 を使用します。一部のデバイスは、単一レジスターでも FC16 のみ受け付けます。その場合は、値を複数レジスターポイントの一部としてマッピングするか、オプションを追加できるようお知らせください。
  • 一部のコントローラーは、書き込まれたパラメーターを不揮発性メモリーに保存します。不揮発性メモリーは、限られた回数しか書き換えられません。エージェントに短い間隔で設定値を書き換えさせないでください。マニュアルに RAM 専用のレジスター、またはリモート設定値用のレジスターがないか確認してください。
  • 通常、読み取りによる副作用はありませんが、読み取るとカウンターやアラームがクリアされるデバイスもあります。そのようなレジスターはマップから除外するか、description に記載してください。
  • Modbus TCP デバイスでは、同時接続数が少数に制限されていることがよくあります。接続を拒否された場合は、ほかの SCADA またはロギングクライアントを終了してください。
  • タイムアウトの原因は、ほとんどの場合、ユニット ID、ボーレート、パリティ、または A/B 配線の誤りです。例外 02 は、デバイスが実装していないアドレスを意味します。例外 03 は、デバイスが内部の制限により値を拒否したことを意味します。
  • pymodbus 3.8 以降で動作します(ユニットのキーワードは 3.10 で slave= から device_id= に変更されました。どちらも処理されます)。
  • 同梱のマップは説明用の例です。実際のデバイスマップの提供を歓迎します。アドレスの出典となったマニュアルのタイトルと改訂版を記載してください。

ハードウェアでの検証

モデルファームウェアインターフェース検証者日付
まだありません:最初の報告者になる

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。