「MCPサーバ - KiCAD」の版間の差分

提供: MochiuWiki : SUSE, EC, PCB

📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

ページの作成:「== 概要 == KiCAD MCPサーバは、電子回路設計ソフトウェアであるKiCADをAIアシスタントから操作可能にするためのModel Context Protocol (MCP) サーバである。<br> このMCPを使用することにより、Claude等のLLMがKiCADプロジェクトの管理、回路図の操作、PCBレイアウトの編集等を実行することができる。<br> <br> KiCAD MCPサーバは、以下に示すような機能を提供する。<br>…」
 
147行目: 147行目:
* RHEL / SUSE
* RHEL / SUSE
*: /usr/lib64/python3.x/site-packages/
*: /usr/lib64/python3.x/site-packages/
* Debian
*: /usr/lib/python3/dist-packages/pcbnew.py
* Debian
* Debian
*: /usr/lib/python3/dist-packages/pcbnew.py
*: /usr/lib/python3/dist-packages/pcbnew.py

2026年1月10日 (土) 21:36時点における版

概要

KiCAD MCPサーバは、電子回路設計ソフトウェアであるKiCADをAIアシスタントから操作可能にするためのModel Context Protocol (MCP) サーバである。
このMCPを使用することにより、Claude等のLLMがKiCADプロジェクトの管理、回路図の操作、PCBレイアウトの編集等を実行することができる。

KiCAD MCPサーバは、以下に示すような機能を提供する。

  • KiCADプロジェクトファイルの読み込みと解析
  • 回路図の情報取得
  • PCB基板レイアウトの情報取得
  • コンポーネントライブラリの管理
  • ネットリストの生成と検証
  • Design Rule Check (DRC) の実行
  • Electrical Rule Check (ERC) の実行


MCPサーバの実装において、PythonまたはNode.jsを使用することができる。
KiCADはPython APIを提供しているため、Pythonによる実装が推奨される。

KiCAD MCPサーバは、Standard I/O (STDIO) トランスポートを使用してローカル環境で動作する。
これにより、Claude DesktopやCursor等のMCPクライアントと統合することができる。

以下の例では、PythonとFastMCPを使用したKiCAD MCPサーバの基本構造を示している。

 from fastmcp import FastMCP
 import pcbnew
 import os
 
 mcp = FastMCP("KiCAD MCP Server")
 
 @mcp.tool()
 def get_board_info(kicad_pcb_path: str) -> dict:
    """KiCAD PCBファイルから基板情報を取得する"""
    try:
       board = pcbnew.LoadBoard(kicad_pcb_path)
 
       info = {
          "board_name": os.path.basename(kicad_pcb_path),
          "num_tracks": board.GetTracks().GetCount(),
          "num_modules": len(list(board.GetFootprints())),
          "board_thickness": board.GetDesignSettings().GetBoardThickness(),
       }
 
       return info
    except Exception as e:
       return {"error": str(e)}
 
 @mcp.tool()
 def run_drc(kicad_pcb_path: str) -> str:
    """Design Rule Checkを実行する"""
    try:
       board = pcbnew.LoadBoard(kicad_pcb_path)
       # DRCの実装
       return "DRC実行完了"
    except Exception as e:
       return f"エラー: {str(e)}"
 
 if __name__ == "__main__":
    mcp.run()


セキュリティでは、KiCADプロジェクトファイルへのアクセス権限の管理、ファイルパスのバリデーション、適切なエラーハンドリング等を行う必要がある。
特に、パストラバーサル攻撃を防ぐため、入力されたファイルパスを適切に検証する必要がある。

パフォーマンスとスケーラビリティでは、大規模なPCBファイルの処理時間の最適化、メモリ使用量の管理が重要である。
また、複数のKiCADプロジェクトを同時に扱う場合は、適切なリソース管理を実装する必要がある。

KiCAD MCPサーバを構築・運用する場合は、以下に示す事柄に注意する。

  • KiCAD Python APIのバージョン互換性の確認
  • STDIOトランスポートでは標準出力 (stdout) にログを出力しない (JSON-RPC通信が破損する)
  • ファイル操作の実行時間を適切に管理して、タイムアウトを設定する
  • エラーハンドリングを適切に実装して、詳細なエラーメッセージを返す
  • KiCADプロジェクトファイルのバックアップを定期的に実施
  • アクセスログの監視
  • ツールのバージョン管理とドキュメントの維持



サーバ環境のインストール

まず、システムの更新を行う。

# RHEL
sudo dnf update

# SUSE
sudo zypper update

# Debian
sudo apt update
sudo apt upgrade


次に、Linuxサーバに必要な基本環境をインストールする。

# RHEL
sudo dnf install curl wget git gcc-c++ make python3 python3-pip

# SUSE
sudo zypper install curl wget git gcc-c++ make python3 python3-pip

# Debian
sudo apt install curl wget git build-essential python3 python3-pip



KiCADのインストール

インストールが完了したら、KiCADのバージョンを確認する。

kicad-cli version


RHEL

RHELでは、EPELリポジトリを有効化してKiCADをインストールする。

sudo dnf install epel-release
sudo dnf install kicad kicad-doc kicad-packages3d


SUSE

SUSEでは、公式リポジトリからKiCADをインストールする。

sudo zypper install kicad kicad-doc kicad-packages3d


Debian

Debianでは、公式リポジトリからKiCADをインストールする。

sudo apt install kicad kicad-doc-ja kicad-libraries


KiCADの最新版をインストールする場合は、公式PPAを使用する。

sudo add-apt-repository ppa:kicad/kicad-7.0-releases
sudo apt update
sudo apt install kicad



Python開発環境の準備

Python仮想環境の作成

プロジェクトディレクトリを作成して、Python仮想環境を設定する。

mkdir -p ~/kicad-mcp-server
cd ~/kicad-mcp-server

python3 -m venv venv


Pythonの仮想環境をアクティベートする。

# Bash / Zshの場合
source venv/bin/activate

# Fishの場合
source venv/bin/activate.fish


必要なPythonライブラリをインストールする。

pip install fastmcp


KiCAD Python APIのインストール

KiCADのPython APIは、KiCADのインストール時に自動的にインストールされる。
Python仮想環境からKiCAD Python APIにアクセスできるように、シンボリックリンクを作成する。

まず、KiCAD Python APIの場所を確認する。

python3 -c "import sys; print([p for p in sys.path if 'kicad' in p.lower()])"


通常、以下に示すディレクトリにインストールされている。

  • RHEL / SUSE
    /usr/lib64/python3.x/site-packages/
  • Debian
    /usr/lib/python3/dist-packages/pcbnew.py


仮想環境からアクセスできるように設定する。

# RHEL / SUSE
ln -s /usr/lib64/python3.x/site-packages/pcbnew.so venv/lib/python3.x/site-packages/

# Debian
ln -s /usr/lib/python3/dist-packages/pcbnew.py venv/lib/python3.x/site-packages/


または、~/.profileファイル等に環境変数 PYTHONPATH を設定する方法もある。

 # ~/.profileファイル等
 
 export PYTHONPATH=/usr/lib/python3/dist-packages:$PYTHONPATH


KiCAD Python APIが正常にインポートできるか確認する。

python3 -c "import pcbnew; print(pcbnew.Version())"



KiCAD MCPサーバの実装

基本的なサーバ構造

KiCAD MCPサーバの基本実装を行う。

 # server.pyファイル
 
 from fastmcp import FastMCP
 import pcbnew
 import os
 from pathlib import Path
 
 mcp = FastMCP("KiCAD MCP Server")
 
 @mcp.tool()
 def load_board(kicad_pcb_path: str) -> dict:
    """KiCAD PCBファイルを読み込み、基本情報を取得する"""
    try:
       if not os.path.exists(kicad_pcb_path):
          return {"error": "ファイルが見つかりません"}
 
       if not kicad_pcb_path.endswith('.kicad_pcb'):
          return {"error": "KiCAD PCBファイルではありません"}
 
       board = pcbnew.LoadBoard(kicad_pcb_path)
 
       info = {
          "board_name": os.path.basename(kicad_pcb_path),
          "layer_count": board.GetCopperLayerCount(),
          "board_thickness": board.GetDesignSettings().GetBoardThickness() / 1000000.0,
          "track_count": board.GetTracks().GetCount(),
          "footprint_count": len(list(board.GetFootprints())),
       }
 
       return info
    except Exception as e:
       return {"error": f"PCB読み込みエラー: {str(e)}"}
 
 @mcp.tool()
 def get_footprints(kicad_pcb_path: str) -> list:
    """基板上のフットプリント一覧を取得する"""
    try:
       board = pcbnew.LoadBoard(kicad_pcb_path)
       footprints = []
 
       for footprint in board.GetFootprints():
          fp_info = {
             "reference": footprint.GetReference(),
             "value": footprint.GetValue(),
             "footprint": footprint.GetFPID().GetLibItemName().GetUniChar(),
             "layer": footprint.GetLayerName(),
          }
          footprints.append(fp_info)
 
       return footprints
    except Exception as e:
       return [{"error": str(e)}]
 
 @mcp.tool()
 def get_net_list(kicad_pcb_path: str) -> list:
    """ネットリストを取得する"""
    try:
       board = pcbnew.LoadBoard(kicad_pcb_path)
       nets = []
 
       for net in board.GetNetInfo().NetsByName():
          net_info = {
             "net_code": net[1].GetNetCode(),
             "net_name": net[1].GetNetname(),
          }
          nets.append(net_info)
 
       return nets
    except Exception as e:
       return [{"error": str(e)}]
 
 @mcp.tool()
 def run_drc(kicad_pcb_path: str) -> dict:
    """Design Rule Checkを実行する"""
    try:
       board = pcbnew.LoadBoard(kicad_pcb_path)
 
       # DRC設定の取得
       drc_settings = board.GetDesignSettings()
 
       # 簡易的なDRCチェック
       track_width = drc_settings.m_TrackMinWidth / 1000000.0
       clearance = drc_settings.m_MinClearance / 1000000.0
 
       result = {
          "min_track_width": track_width,
          "min_clearance": clearance,
          "status": "DRCチェック完了",
       }
 
       return result
    except Exception as e:
       return {"error": f"DRCエラー: {str(e)}"}
 
 @mcp.tool()
 def get_board_outline(kicad_pcb_path: str) -> dict:
    """基板外形の寸法を取得する"""
    try:
       board = pcbnew.LoadBoard(kicad_pcb_path)
       bbox = board.GetBoardEdgesBoundingBox()
 
       dimensions = {
          "width": bbox.GetWidth() / 1000000.0,
          "height": bbox.GetHeight() / 1000000.0,
          "area": (bbox.GetWidth() * bbox.GetHeight()) / 1000000000000.0,
       }
 
       return dimensions
    except Exception as e:
       return {"error": str(e)}
 
 @mcp.tool()
 def export_gerber(kicad_pcb_path: str, output_dir: str) -> str:
    """Gerberファイルを出力する"""
    try:
       board = pcbnew.LoadBoard(kicad_pcb_path)
 
       if not os.path.exists(output_dir):
          os.makedirs(output_dir)
 
       plot_controller = pcbnew.PLOT_CONTROLLER(board)
       plot_options = plot_controller.GetPlotOptions()
 
       plot_options.SetOutputDirectory(output_dir)
       plot_options.SetPlotFrameRef(False)
       plot_options.SetLineWidth(pcbnew.FromMM(0.1))
 
       # レイヤーごとにプロット
       layers = [
          ("F.Cu", pcbnew.F_Cu, "Top Copper"),
          ("B.Cu", pcbnew.B_Cu, "Bottom Copper"),
          ("F.Mask", pcbnew.F_Mask, "Top Soldermask"),
          ("B.Mask", pcbnew.B_Mask, "Bottom Soldermask"),
          ("F.SilkS", pcbnew.F_SilkS, "Top Silkscreen"),
          ("B.SilkS", pcbnew.B_SilkS, "Bottom Silkscreen"),
          ("Edge.Cuts", pcbnew.Edge_Cuts, "Board Outline"),
       ]
 
       for layer_info in layers:
          plot_controller.SetLayer(layer_info[1])
          plot_controller.OpenPlotfile(layer_info[0], pcbnew.PLOT_FORMAT_GERBER, layer_info[2])
          plot_controller.PlotLayer()
 
       plot_controller.ClosePlot()
 
       return f"Gerberファイルを {output_dir} に出力しました"
    except Exception as e:
       return f"エラー: {str(e)}"
 
 if __name__ == "__main__":
    mcp.run()


エラーハンドリング

本番環境では、詳細なエラーハンドリングを定義する。

 import logging
 from typing import Optional
 
 # ログ設定 (stderrに出力)
 logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[logging.StreamHandler()]
 )
 
 logger = logging.getLogger(__name__)
 
 def safe_load_board(kicad_pcb_path: str) -> Optional[pcbnew.BOARD]:
    """安全にKiCAD PCBファイルを読み込む"""
    try:
       # パスバリデーション
       path = Path(kicad_pcb_path).resolve()
 
       # パストラバーサル攻撃を防ぐ
       if '..' in str(path):
          logger.error(f"無効なパス: {kicad_pcb_path}")
          return None
 
       if not path.exists():
          logger.error(f"ファイルが存在しません: {kicad_pcb_path}")
          return None
 
       if not str(path).endswith('.kicad_pcb'):
          logger.error(f"KiCAD PCBファイルではありません: {kicad_pcb_path}")
          return None
 
       board = pcbnew.LoadBoard(str(path))
       logger.info(f"PCBファイルを読み込みました: {kicad_pcb_path}")
 
       return board
    except Exception as e:
       logger.exception(f"PCB読み込みエラー: {str(e)}")
       return None



MCP Inspectorによるテスト

MCP Inspectorを使用して、KiCAD MCPサーバのツールをテストする。

まず、MCP Inspectorをインストールする。

pip install mcp-inspector


MCP Inspectorを起動する。

mcp-inspector python server.py


Webブラウザが自動的に開いて、インスペクターのインターフェースが表示される。

テスト用のKiCADプロジェクトファイルを準備して、各ツールの動作を確認する。

  • load_board
    PCBファイルの基本情報を取得
  • get_footprints
    フットプリント一覧を取得
  • get_net_list
    ネットリスト一覧を取得
  • run_drc
    DRCチェックの実行
  • get_board_outline
    基板外形の寸法を取得
  • export_gerber
    Gerberファイルの出力



クライアント接続設定

Claude Desktopからの接続

Claude Desktopの設定ファイルを編集する。

設定ファイルの場所は、以下の通りである。

  • Linuxの場合
    ~/.config/Claude/claude_desktop_config.json
  • Windowsの場合
    %APPDATA%\Claude\claude_desktop_config.json


設定ファイルの内容を編集する。

 {
   "mcpServers": {
     "kicad-server": {
       "command": "/home/<ユーザ名>/kicad-mcp-server/venv/bin/python",
       "args": ["/home/<ユーザ名>/kicad-mcp-server/server.py"],
       "env": {
         # RHEL / SUSEの場合
         "PYTHONPATH": "/usr/lib64/python3.x/site-packages"
 
         # Debianの場合
         "PYTHONPATH": "/usr/lib/python3/dist-packages"
       }
     }
   }
 }


環境変数 PYTHONPATH を設定することにより、KiCAD Python APIにアクセスできるようにする。

Claude Desktopを再起動して、KiCAD MCPサーバが利用可能であることを確認する。


Systemdサービスファイルの作成

KiCAD MCPサーバをシステムサービスとして常時起動させる場合、systemdユニットファイルを作成する。

sudo vi /etc/systemd/system/kicad-mcp-server.service


 # /etc/systemd/system/kicad-mcp-server.serviceファイル
 
 [Unit]
 Description=KiCAD MCP Server
 After=network.target
 
 [Service]
 Type=simple
 User=<実行する任意のユーザ名>
 WorkingDirectory=/home/<ユーザ名>/kicad-mcp-server
 ExecStart=/home/<ユーザ名>/kicad-mcp-server/venv/bin/python server.py
 Restart=always
 RestartSec=10
 StandardOutput=journal
 StandardError=journal
 
 # 環境変数の設定
 ## Debianの場合
 Environment="PYTHONPATH=/usr/lib64/python3.x/site-packages"
 
 ## Debianの場合
 Environment="PYTHONPATH=/usr/lib/python3/dist-packages"
 
 Environment="DISPLAY=:0"
 
 [Install]
 WantedBy=multi-user.target


サービスを有効化して起動する。

sudo systemctl daemon-reload
sudo systemctl enable kicad-mcp-server
sudo systemctl start kicad-mcp-server


サービスの状態を確認する。

sudo systemctl status kicad-mcp-server


ログを確認する。

sudo journalctl -u kicad-mcp-server -f



セキュリティ設定

ファイルアクセスの制限

KiCAD MCPサーバがアクセス可能なディレクトリを制限することが推奨される。

 # 許可されたディレクトリのリスト
 ALLOWED_DIRECTORIES = [
    "/home/<ユーザ名>/kicad-projects",
    "/home/<ユーザ名>/shared-projects",
 ]
 
 def is_path_allowed(file_path: str) -> bool:
    """ファイルパスが許可されたディレクトリ内にあるか確認する"""
    try:
       resolved_path = Path(file_path).resolve()
 
       for allowed_dir in ALLOWED_DIRECTORIES:
          allowed_path = Path(allowed_dir).resolve()
          if resolved_path.is_relative_to(allowed_path):
             return True
 
       return False
    except Exception:
       return False
 
 @mcp.tool()
 def load_board_secure(kicad_pcb_path: str) -> dict:
    """セキュアなPCBファイル読み込み"""
    if not is_path_allowed(kicad_pcb_path):
       return {"error": "このファイルへのアクセスは許可されていません"}
    
    # 以降の処理


入力データのバリデーション

ツールのパラメータに対して、適切なバリデーションを行う。

 import re
 
 def validate_file_path(path: str) -> bool:
    """ファイルパスの妥当性を検証する"""
    # パストラバーサル攻撃を防ぐ
    if '..' in path:
       return False
 
    # 許可された拡張子のみ
    allowed_extensions = ['.kicad_pcb', '.kicad_pro', '.kicad_sch']
    if not any(path.endswith(ext) for ext in allowed_extensions):
       return False
 
    # 不正な文字を含まない
    if not re.match(r'^[a-zA-Z0-9._\-/]+$', path):
       return False
    
    return True



バックアップとリストア

KiCADプロジェクトのバックアップ

定期的にKiCADプロジェクトをバックアップする。

 #!/usr/bin/env sh
 ## backup-kicad-projects.shファイル
 
 BACKUP_DIR="/var/backups/kicad-projects"
 DATE=$(date +%Y%m%d_%H%M%S)
 PROJECT_DIR="/home/username/kicad-projects"
 
 # バックアップディレクトリの作成
 mkdir -p $BACKUP_DIR
 
 # プロジェクトディレクトリの圧縮
 tar -czf "$BACKUP_DIR/kicad-projects_$DATE.tar.gz" -C $(dirname $PROJECT_DIR) $(basename $PROJECT_DIR)
 
 # 30日以上前のバックアップを削除
 find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete
 
 echo "バックアップ完了: kicad-projects_$DATE.tar.gz"


バックアップスクリプトを実行可能にする。

chmod u+x backup-kicad-projects.sh


cronジョブとして設定する。

crontab -e


# 毎日午前3時にバックアップを実行
0 3 * * * /path/to/backup-kicad-projects.sh



トラブルシューティング

KiCAD Python APIがインポートできない

  • KiCADが正しくインストールされているか確認する。
    kicad-cli version
  • 環境変数PYTHONPATH が正しく設定されているか確認する。
    echo $PYTHONPATH
  • Python仮想環境からKiCAD Python APIへのシンボリックリンクが正しいか確認する。
    ls -la venv/lib/python3.x/site-packages/pcbnew*


PCBファイルの読み込みに失敗する

  • ファイルパスが正しいか確認する。
  • ファイルの読み取り権限があるか確認する。
    ls -la /path/to/file.kicad_pcb
  • KiCADのバージョンとファイルフォーマットの互換性を確認する。


Claude Desktopから接続できない

  • 設定ファイルのパスが正しいか確認する。
  • Python仮想環境のパスが正しいか確認する。
  • 環境変数 PYTHONPATH が設定されているか確認する。
  • STDIOトランスポートの場合、標準出力にログを出力していないか確認する。


Gerberファイルの出力に失敗する

  • 出力ディレクトリの書き込み権限があるか確認する。
  • ディスク容量が十分にあるか確認する。
  • KiCADのプロットコントローラの設定を確認する。



パフォーマンス最適化

大規模PCBファイルの処理

大規模なPCBファイルを処理する場合、メモリ使用量と処理時間に注意する必要がある。

 import gc
 
 @mcp.tool()
 def process_large_board(kicad_pcb_path: str) -> dict:
    """大規模なPCBファイルを効率的に処理する"""
    try:
       board = pcbnew.LoadBoard(kicad_pcb_path)
 
       # 必要な情報のみを抽出
       result = extract_board_info(board)
 
       # ボードオブジェクトを明示的に削除
       del board
       gc.collect()
 
       return result
    except Exception as e:
       return {"error": str(e)}


キャッシングの実装

頻繁にアクセスされるデータをキャッシュすることにより、パフォーマンスを向上させる。

 from functools import lru_cache
 import hashlib
 
 def get_file_hash(file_path: str) -> str:
    """ファイルのハッシュ値を計算する"""
    with open(file_path, 'rb') as f:
       return hashlib.md5(f.read()).hexdigest()
 
 @lru_cache(maxsize=10)
 def get_cached_board_info(file_path: str, file_hash: str) -> dict:
    """キャッシュされたボード情報を取得する"""
    board = pcbnew.LoadBoard(file_path)
    # 情報を抽出
    return extract_board_info(board)
 
 @mcp.tool()
 def load_board_cached(kicad_pcb_path: str) -> dict:
    """キャッシュを使用してPCBファイルを読み込む"""
    try:
       file_hash = get_file_hash(kicad_pcb_path)
       return get_cached_board_info(kicad_pcb_path, file_hash)
    except Exception as e:
       return {"error": str(e)}



外部リンク