ESP-IDF MCP について
ESP-IDF MCPは、接続したハードウェア上でESP-IDFファームウェアをビルド、テストするエージェント向けのローカルMCPサーバーです。ビルド、シリアル書き込みと監視、チップ情報、実機テストに対応します。
主な機能
- 01ESP-IDFプロジェクトのビルドとクリーン
- 02ファームウェア書き込みとシリアルログ監視
- 03接続チップとフラッシュ情報の取得
- 04プロジェクト作成と同梱サンプルの一覧
- 05コンポーネント依存関係の管理と実機テスト
活用シーン
- 01ESP-IDFプロジェクトのファームウェアをビルド
- 02ボードへ書き込み起動ログを確認
- 03接続チップの情報を調べる
- 04実機でpytest-embeddedテストを実行
MCP 対応
ESP-IDFプロジェクト、シリアルデバイス、ハードウェアテスト用のツールをMCPクライアントに提供します。接続中のシリアルポートを列挙するproject://devicesリソースもあります。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
esp-idf-mcp
AI エージェントが実機上で ESP-IDF プロジェクトをビルド、フラッシュ、監視できる Model Context Protocol(MCP)サーバーです。ソースコードから起動ログまで、エンドツーエンドで対応します。
エージェントがファームウェアコードを 書く だけでなく、このサーバーを使えば一連の作業を完了できます。コンパイル → シリアル経由でフラッシュ → 起動ログの取得 → pytest-embedded によるハードウェアテストを、エージェントのツールセットから離れることなく実行できます。
クイックスタート(Windows + Codex)
要件: ESP-IDF、Python 3.9 以降、MCP 対応の Codex クライアントが必要です。ボードの接続は、フラッシュ、シリアルモニタリング、ハードウェア・イン・ザ・ループテストを行う場合にのみ必要です。
-
このリポジトリをクローンし、Codex が使用する Python 環境にインストールします。
git clone https://github.com/Maty403/esp-idf-mcp.git cd esp-idf-mcp python -m pip install . -
Codex にサーバーを追加します。デスクトップアプリ、CLI、IDE 拡張機能は MCP 設定を共有します。ターミナルから次を実行します。
codex mcp add esp-idf -- esp-idf-mcp codex mcp listesp-idf-mcpが PATH にない場合は、%USERPROFILE%\.codex\config.tomlを開き、両方のパスを書き換えて次の内容を追加します。pip install .を実行したときと同じ Python 環境を使用してください。[mcp_servers.esp-idf] command = "C:\\path\\to\\python.exe" args = ["C:\\path\\to\\esp-idf-mcp\\esp_idf_mcp.py"] -
Codex を再起動し、ESP-IDF プロジェクトを開いて、**「この ESP-IDF プロジェクトをビルドして」**と依頼します。デスクトップアプリでは、Settings → MCP servers を確認するか、
/mcpと入力してサーバーが接続されていることを確認してください。
デモのワークフロー
ESP-IDF プロジェクトを開き、ボードを接続した状態で、次を試してください。
- 「接続されたチップの情報を読み取り、シリアルデバイスを一覧表示して」
- 「このプロジェクトをビルドして」
- 「このプロジェクトを COM3 にフラッシュし、起動ログを監視して、アプリケーションの出力を要約して」
COM3 は、お使いの環境で表示される正しいポートに置き換えてください。フラッシュする前に、ターゲットボードとポートを確認してください。
このサーバーの位置付け
ESP-IDF のハードウェアワークフロー向けにコミュニティが開発したローカル MCP サーバーです。AI エージェントを使って、ファームウェアのビルド、シリアル接続されたボードとのやり取り、ハードウェア・イン・ザ・ループテストの実行を、同じワークフロー内で行えます。
機能比較
Espressif の組み込み ESP-IDF Tools MCP サーバーとの比較です(ドキュメント確認日:2026-10-26)。
| ワークフロー | 組み込み ESP-IDF Tools MCP | esp-idf-mcp |
|---|---|---|
| ターゲットの設定、ビルド、フラッシュ、クリーン | 対応 | 対応 |
| プロジェクトの作成 | サンプルテンプレート | 最小構成のテンプレートまたは同梱の ESP-IDF サンプル |
| デバイスの監視 | 期待される出力を待機。シリアルログ全体を保存 | 読み取り/送信/終了が可能な永続セッション、差分表示と全ログ表示、ボーレート検出、USB 再接続処理 |
| プロジェクトとデバイスのコンテキスト | プロジェクト設定、ビルド状態、接続デバイスのリソース | 接続デバイスのリソースに加え、チップモデル、リビジョン、クリスタル、MAC、フラッシュの詳細 |
| コンポーネントとハードウェアテスト | 組み込み Tools MCP のツールセットには記載なし | 同梱サンプルの閲覧、コンポーネント依存関係の追加/削除、pytest-embedded によるハードウェアテストの実行 |
この表では、ローカルの Tools MCP サーバーと本プロジェクトを比較しています。Espressif が別途提供する Documentation MCP サーバーと Component Registry MCP サーバーは、ドキュメントの参照やコンポーネントの検索に利用でき、どちらのローカルツールサーバーとも併用できます。
機能
- ESP-IDF を設定不要で検出 — IDF のルート、ツールディレクトリ、Python 仮想環境を自動で検出します(環境変数を優先し、設定されていない場合は
D:\esp、C:\esp、~/espの中から最新のインストールを検出します)。ツールチェーンのパスはバージョンのグロブパターンで照合するため、ESP-IDF やツールチェーンをアップグレードしてもスクリプトを編集する必要はありません。 idf.py buildでビルド — 手動ビルドとまったく同じ方法でビルドするため、追加の設定書き換えはありません。そのため、sdkconfigとsdkconfig.defaultsは公式のアップストリームと同じ動作を保ちます。デフォルト設定ファイルは新しいsdkconfigの初期値として適用されます(汎用のsdkconfig.defaultsに加え、汎用ファイルがある場合はsdkconfig.defaults.<target>も適用されます)。以降のビルドでは、すでにsdkconfigにある値が優先されます。sdkconfigを手動で編集した場合も、公式の ninjaRERUN_CMAKEフローを通じて反映されます。- フラッシュと自動モニターを一度に実行 —
esptoolでフラッシュし(build/flash_argsを読み込みます)、ハードリセット後の起動を待ってから、そのポートで永続的なモニターセッションを開き、すぐに戻ります(ボードはリセットされるため、セッションには起動直後のログのみが保持されます)。monitor_readでポーリングしてください。対象ポートには指定したポートを使用します。省略時は自動検出しますが、接続されている COM1 以外のポートが 1 つだけの場合に限ります。それ以外の場合は呼び出しを拒否し、候補を一覧表示します。フラッシュ前に閉じるのはそのポートのモニターセッションのみです(開いているセッションがない場合は閉じる処理を省略します)。ほかのボードには一切影響しません。 - 実機からチップ情報を取得 —
read_chip_infoはesptoolを使って、チップモデル、リビジョン、機能、クリスタル、MAC アドレス、フラッシュのベンダー/デバイス/サイズを報告し、その後ボードをハードリセットして実行中のアプリに戻します。 - ボーレートを自動検出 — シリアルキャプチャのたびに、プロジェクトの
sdkconfigからCONFIG_ESP_CONSOLE_UART_BAUDRATEを読み取ります(ハードコードされたデフォルト値はありません)。そのため、ログが文字化けすることはありません。 - セッションベースのシリアルモニター —
monitor_open/monitor_read/monitor_send/monitor_close:新しい行だけをポーリングする、永続的でノンブロッキングなセッションです。monitor_close(session_id)は、指定したセッション、または指定したポート上のすべてのセッションのみを解放します。flash_projectはフラッシュのたびに自動でセッションを開くため、起動ログをいつでもポーリングできます。セッションは自動的に解放されます。読み取り/書き込みがない状態がidle_release秒間(デフォルトは 30 秒。呼び出しごとに上書き可能)続くとポートを解放するため、放置されたセッションが COM ポートを占有し続けることはありません。 - アプリケーション層のログ表示 —
monitor_readは、実行時マーカーmain_task: Returned from app_main()から出力を開始します。それより前のすべてのログ(ブート ROM/ブートローダー/コンポーネントのログと、app_main()の初期化出力)は件数にまとめられ(ヘッダーにN lines folded before app startと表示されます)、マーカーとその後のすべての行(タスク、wifi、mqtt、通常のprintf)は 1 行ずつ出力されます。マーカーを含まない増分ログは、単なる続きの行であればそのまま出力し、ブート中であれば折りたたんで件数にまとめます。 fullによる全件表示と永続的な全ログ —monitor_read(full=True)は、バッファ内に保持されているすべての内容をそのまま出力します(層の分割や折りたたては行わず、タイムスタンプも変更しません)。増分読み取りのカーソルは消費されないため、2 つの読み取りモードが干渉することはありません。さらに、すべてのシリアル行はセッションログファイル(<project>/.esp_monitor_full.log)に書き込まれるため、バッファからの消去、USB の再認識、ボードのリセット、セッションの終了後も履歴が残ります。読み取りによって情報が失われることはありません。折りたたまれた行は必ずヘッダーに件数が表示され、バッファから消去された内容はファイルに残ります。- エージェントに適した出力 — ANSI カラーエスケープを元の段階で除去し、連続する重複行を
<first line> *Nにまとめて、繰り返しの内容を件数のすぐ隣に表示します(先頭のI (12345)プレフィックスは比較時に無視されるため、異なるミリ秒に記録された行もまとめられます)。長い出力では関連する末尾のみを残し、消去またはスキップされた件数をヘッダーに報告するため、行が黙って捨てられることはありません。 - USB の再認識後も動作を継続 — リセット後にポートが一度消えてから再表示される場合(ESP32-S2/USB-OTG)でも、読み取りループは最大 10 秒間再接続を試み、古いバッファ内のログを消去します。
- ハードウェア・イン・ザ・ループテスト — 実機のボードに対して
pytest-embeddedスイートを実行します。 Windows のusbser.sysに関する回避策が含まれています(RTS のみの制御転送では DTR を再度アサートする必要があります)。これにより、CH340 スタイルのアダプターだけでなく、USB-CDC ポートでもリセットが機能します。
ツール
| ツール | 用途 |
|---|---|
build_project | idf.py build(手動ビルドと同じで、設定は書き換えません) |
flash_project | esptool による書き込み。port が省略されると自動検出されます(COM1 以外のポートがちょうど 1 つ接続されている場合のみ。そうでない場合は呼び出しを拒否し、候補を一覧表示します)。書き込み前にそのポートのモニターセッションのみを閉じ、その後、monitor_read 用にそのポートで永続的なモニターセッションを開きます(ボーレートは sdkconfig から取得) |
read_chip_info | チップのモデル、リビジョン、機能、クロック水晶、MAC、フラッシュのベンダー/デバイス/サイズ |
set_target | idf.py set-target(esp32、esp32s3、esp32c2、…) |
create_project / list_examples | 新しいプロジェクトを作成(最小テンプレートまたは同梱の公式サンプル)。インストール済み IDF に含まれるサンプルを参照 |
add_dependency / remove_dependency | idf_component.yml の ESP コンポーネントマネージャー依存関係を管理 |
clean_project | インクリメンタルクリーンまたは fullclean |
monitor_open / monitor_read / monitor_send / monitor_close | 永続的な対話型シリアルセッション。monitor_read は Returned from app_main() から出力を開始し(それ以前の内容は件数にまとめられます)、連続する重複行を <first line> *N としてまとめます。保持されている内容をすべてカーソル位置に依存せずダンプする full=True、ミリ秒のプレフィックスを保持する timestamp=True を指定できます。また、すべての行を <project>/.esp_monitor_full.log に書き込みます。monitor_close(session_id)(またはポート名のみ)を指定すると、そのセッション/ポートのみを解放します。読み取り/書き込みがない状態が idle_release 秒(デフォルトは 120 秒)続くと、セッションは自動的に解放されます |
run_pytest | pytest-embedded のハードウェアテストを実行 |
project://devices(リソース) | 接続されているシリアルポートを一覧表示 |
ツールのリファレンス
各ツールがエージェントに公開する説明の全文:
build_project(project_dir, timeout=600) — idf.py build を使用して ESP-IDF プロジェクトをビルドします(手動ビルドと同じです)。timeout はビルド全体の制限時間(秒)で、デフォルトは 600 です。タイムアウトするとプロセスツリーを終了し、抽出したエラー行を含む失敗結果を返します。呼び出しごとに、✅/❌ の判定を明示して返します。すべての出力は常に <project_dir>/.esp_build.log に保存され、実行のたびに上書きされます。設定は変更されません。新しい sdkconfig の初期値には sdkconfig.defaults が使われ、既存の sdkconfig の値が優先されます。
flash_project(project_dir, port=None, monitor=True, wait_after_flash=2.0, timeout=600) — esptool を直接使用して、ビルド済みプロジェクトを書き込みます(build/flash_args を読み取ります)。書き込み前に、対象ポートのモニターセッションは自動的に閉じられるため、手動で monitor_close を呼び出す必要はありません。port が省略されると自動検出されますが、COM1 以外のポートがちょうど 1 つ接続されている場合に限ります。複数のポートが接続されている場合は呼び出しを拒否して一覧表示するため、誤ったボードに書き込まれることはありません。monitor=True の場合は、書き込み後に永続的なセッションを開きます(ボーレートは sdkconfig から取得)。wait_after_flash を設定すると、モニターを開く前にハードリセット後の起動が完了するまで待機するため、セッションには起動時のログが最初から記録されます。timeout は書き込み全体の制限時間(秒)で、デフォルトは 600 です。すべての出力は常に <project_dir>/.esp_flash.log に保存され、実行のたびに上書きされます。
create_project(path, example='') — 絶対パス path に新しい ESP-IDF プロジェクトを作成します(パスが存在しないか、空である必要があります)。example を指定すると(例:'get-started/hello_world')、インストール済み IDF に同梱されている公式サンプルからプロジェクトをコピーします。list_examples でサンプルを参照できます。ルートの project() 名が見つかった場合は、新しいディレクトリ名に変更されます。example を指定しない場合は、idf.py create-project を使って最小テンプレートのプロジェクトを作成します。どちらも完全にオフラインで実行されます。レジストリのコンポーネントを新しいプロジェクトに取り込むには、後から add_dependency を呼び出してください(コンポーネントは次回のビルド時にダウンロードされます)。
list_examples(category='') — インストール済みの IDF に含まれる ESP-IDF の公式サンプルを一覧表示します。引数なしの場合はカテゴリ(get-started、wifi、peripherals、…)を一覧表示します。カテゴリを指定すると、その中にあるサンプルを create_project(example=…) ですぐに使用できるパスとして一覧表示します。
read_chip_info(port=None, baud=115200) — esptool を使用して、チップのモデル、リビジョン、機能、水晶発振器の周波数、MAC アドレス、およびフラッシュのベンダー/デバイス/サイズを取得します。ボードは一時的にダウンロードモードに切り替わり、その後ハードリセットされて実行中のアプリに戻ります。PSRAM の詳細はここでは取得できません。代わりに monitor_open でブートログを読み取ってください。
monitor_open(port, reset=True, project_dir=None, idle_release=120, baud=0) — 永続的なシリアルモニターセッションを開き、すぐに戻ります(非ブロッキング)。reset=True の場合、バッファーをクリアしてからボードをハードリセットするため、セッションは新たな起動から始まります。baud が 0 より大きい場合は指定値をそのまま使用し、自動検出をスキップします。デフォルトの baud=0 の場合、project_dir の sdkconfig(CONFIG_ESP_CONSOLE_UART_BAUDRATE、未設定時は 115200)からボーレートを自動検出します。project_dir を指定すると、セッションの全ログを <project_dir>/.esp_monitor_full.log にも保存します(セッションを開くたびに最初から書き直されます。セッション中は各行の受信時にフラッシュされるため、バッファーからの削除、再接続、ボードのリセット後も履歴が残ります。プロジェクトディレクトリを指定しない場合、セッションは全ログファイルを保持しません)。セッション ID は PORT@BAUD(例:COM17@115200)です。idle_release は、monitor_read/monitor_send が呼び出されない状態が続いた場合のセッション有効期間を秒単位で設定します(デフォルトは 120 秒)。この時間を過ぎるとセッションは自動停止してポートを解放します。そのため、クライアントが放置したセッション(MCP クライアントは stdio パイプを閉じずにサーバープロセスを動作させ続ける傾向があります)が COM ポートを占有し続けることはありません。読み取りループがポートを再取得してしまう可能性があるため、USB の抜き差しをまたいだ場合も同様です。monitor_read/monitor_send を呼び出すとタイマーがリセットされます。長い中断を挟む場合は値を大きくするか、終了時に monitor_close を明示的に呼び出してください。呼び出しで No session と報告された場合は、monitor_open を再度実行してください。全履歴はログファイルに保存されています。
monitor_read(session_id, full=False, timestamp=False, max_lines=0, match='') — 前回の読み取り以降に届いた行を読み取ります。出力は実行時マーカー main_task: Returned from app_main() から始まります。それより前のすべて(ブートログと app_main() の初期化時の出力)は件数にまとめられ、N lines folded before app start として報告されます。マーカーとそれ以降の各行は、1 行ずつ表示されます。隣接する重複行は <first line> *N の形式にまとめられるため、繰り返された内容は常に件数の横に表示されます(先頭の I (12345) は比較時に無視されるため、記録された時刻が異なっていても同じ行としてまとめられます)。マーカーのない増分は、単なる続きであればそのまま表示され、ブート中であればまとめて省略されます。full=True にすると、カーソルに依存しない全件ダンプに切り替わります。リングバッファーに保持されているすべての行がそのまま出力され(まとめ処理なし、レイヤー分割なし、タイムスタンプ変更なし)、増分カーソルは進みません。そのため、まとめ表示と全件表示が互いに干渉することはありません。max_lines は返される末尾の行数を制限します(0 = 保持されているすべての行)。ヘッダーには、該当する場合、M evicted by buffer cap と K older skipped (showing last T) が表示されるほか、全ログファイルのパスも表示されます。リングバッファーから削除された行も失われることはなく、ファイルに保存されています。timestamp=True にするとミリ秒のプレフィックスが保持されます(デフォルトでは削除され、TAG: msg になります)。
match は正規表現で出力をフィルタリングします(大文字と小文字を区別せず、レベル/ms のプレフィックスを除いた行テキストに対して照合します。| で選択肢を区切ります。例:match='heap|wifi|dhcp')。設定すると、アプリ起動時の折りたたみ処理はスキップされ、一致する行のみが返されます。ノイズの多いログから特定のトピックを取り出すのに便利です。診断に重要な行は、一致するものがなくても常に通過します。すべての ESP_LOG エラーレベルの行(E (…))に加え、ログレベルのプレフィックスを持たないパニックハンドラーの出力(Guru Meditation/panic'ed、abort() was called、assert failed、Backtrace:、スタックカナリア、ウォッチドッグおよびブラウンアウトのトリガー、CORRUPT HEAP、コアダンプ、リセット理由、Rebooting…)が対象です。フィルタリングされた表示でクラッシュが隠れることはありません。フィルターで除外された行も増分カーソルでは読み取られます。同じフィルターでバッファーに保持されたすべての内容を再スキャンするには、match と full=True を組み合わせてください。
monitor_send(session_id, data, press_enter=True) — デバイスのシリアル入力にテキストを書き込みます(シェルコマンド、メニュー選択など)。press_enter は CRLF を追加します。
monitor_close(session_id) — 1 つのセッション(COM17@115200)またはベアポート(COM17)上のすべてのセッションを解放します。すべてを一括で解放するモードはありません。
set_target(project_dir, target) — esp32 / esp32s3 / esp32c2 / … に対して idf.py set-target を実行します。idf.py は既存の sdkconfig を sdkconfig.old に名前変更し、新しいターゲット用の設定ファイルを新たに生成します。
add_dependency(project_dir, dependency, component=None, path=None) / remove_dependency(project_dir, dependency) — ESP コンポーネントマネージャーのマニフェスト idf_component.yml を管理します。コンポーネントは次回のビルド時に取得または削除されます。
clean_project(project_dir, full=False) — idf.py clean または fullclean を実行します(ビルド成果物のみが対象です。sdkconfig は変更されません)。
run_pytest(project_dir, ...) — 実際のボードに対して pytest-embedded のハードウェアテストを実行します(フラッシュ+操作+シリアル出力の検証)。
リソース project://devices — 接続されているシリアルポートの JSON リストです。
要件
- ESP-IDF(Windows 上の v6.1 に対して開発されています。他の構成でも、自動検出または以下の環境変数でインストール先を検出できれば動作します)
mcpとpyserialを含む Python ≥ 3.9- 任意の MCP クライアント(Claude Desktop、Cursor、VS Code など)
セットアップ
オプション A — パッケージとしてインストール
pip install .
オプション B — 単一ファイルを直接実行
mcp と pyserial をインストールした任意の Python を使い、MCP クライアントの接続先として esp_idf_mcp.py を指定してください(ESP-IDF の venv が適しています)。
MCP クライアントへの登録
{
"mcpServers": {
"esp-idf": {
"command": "python",
"args": ["C:\\path\\to\\esp_idf_mcp.py"]
}
}
}
(pip でインストールした場合は、引数なしで "command": "esp-idf-mcp" を指定してください)
設定
起動時に ESP-IDF の場所を自動検出します。まず環境変数を確認し、次に D:\esp\<ver>\esp-idf、C:\esp\<ver>\esp-idf または ~/esp/<ver>/esp-idf の下から最新のインストールを探します。ツールディレクトリは、見つからない場合に C:\Espressif\tools、次に D:\espressif\tools を使用します。すべてのパスは外部から上書きできます。
| 環境変数 | 意味 |
|---|---|
IDF_PATH | ESP-IDF フレームワークのルート(自動検出より優先) |
IDF_PYTHON_ENV_PATH | ESP-IDF の Python 仮想環境(デフォルト:<tools>\python\*\venv の下にある最新のもの) |
IDF_TOOLS_PATH | Espressif ツールディレクトリ(デフォルト:C:\Espressif\tools、次に D:\espressif\tools) |
ESP_IDF_VERSION | バージョンラベル — IDF ディレクトリ名から先頭の v を除いて取得します(v6.1 → 6.1)。コンポーネントマネージャーが解析できるようにするための値です |
IDF_COMPONENT_MANAGER | idf.py add-dependency とマネージドコンポーネントを解決できるよう、1 に固定されます |
ツールパスの下にあるツールチェーンディレクトリ(xtensa/riscv GCC、CMake、Ninja、ccache、idf-exe、esp-rom-elfs)は、バージョンの glob パターンで照合され、PATH の先頭に追加されます。起動時には、診断用の 1 行(IDF_PATH=… TOOLS=… PYENV=…)が stderr に出力されます。
エージェントの一般的なワークフロー
read_chip_info → set_target(esp32s3) → build_project → flash_project(port="COM17")
→ monitor_read(session_id) → iterate on code → run_pytest
サポート
このサーバーによってフラッシュデバッグの試行錯誤を減らせたら、スターを付けるか、作者にコーヒーをごちそうしてください。
| Alipay | Binance Pay |
|---|---|
![]() | ![]() |
| スキャンして支払う | Binanceアプリでスキャン |
| USDT(TRC-20) | USDT(BEP-20 / BSC) |
|---|---|
![]() | ![]() |
スキャンするか、アドレスをコピーしてください:TL4j1mRbfjQBEGpqBbRTEYHvJABxCi3tkQ | スキャンするか、アドレスをコピーしてください:0x1572a9a6ce3da8b55c6cfc67e5b0557f3f10d423 |
USDT:BSC / BEP-20でのみ送金してください。任意のEVMウォレットでアドレスをスキャンするか、直接コピーしてください。
ライセンス
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。



