【Dify × MCP】ローカルでExcel操作を自動化する方法
はじめに
Difyでワークフローを作成していると、「Excelファイルを操作したい」と思うことはありませんか?
しかし、Difyはサンドボックス環境で動作するため、直接ローカルのファイルを操作することができません。
そこで今回は、MCP(Model Context Protocol)サーバーを使って、Difyからローカル環境のExcelファイルを操作する方法を紹介します。
MCPとは?
MCP(Model Context Protocol)は、AIモデルが外部ツールやデータソースと連携するための標準プロトコルです。MCPサーバーを立てることで、Difyのワークフローから様々な外部機能を呼び出すことができます。
前提条件
- Docker / Docker Desktop がインストール済み
- Python 3.10以上がインストール済み
- Dify が Docker で起動済み
構築手順
Step 1: プロジェクトディレクトリの作成
mkdir -p mcp-excel-server
cd mcp-excel-server
Step 2: サーバーファイルの作成
server.py を作成します。
#!/usr/bin/env python3
"""
Excel操作用MCPサーバー
Difyからローカルでエクセルを操作するためのサーバー
"""
import json
import os
from typing import Any
from mcp.server.fastmcp import FastMCP
from openpyxl import Workbook, load_workbook
# MCPサーバー作成
mcp = FastMCP("excel-server")
# デフォルトの出力ディレクトリ
OUTPUT_DIR = os.path.expanduser("~/Documents/DifyExcel")
os.makedirs(OUTPUT_DIR, exist_ok=True)
@mcp.tool()
def create_excel(filename: str, data: list[list[str]], sheet_name: str = "Sheet1") -> str:
"""
新しいExcelファイルを作成します。
Args:
filename: ファイル名(例: "report.xlsx")
data: 2次元配列のデータ(例: [["A1", "B1"], ["A2", "B2"]])
sheet_name: シート名(デフォルト: "Sheet1")
Returns:
作成したファイルのパス
"""
wb = Workbook()
ws = wb.active
ws.title = sheet_name
for row_idx, row in enumerate(data, 1):
for col_idx, value in enumerate(row, 1):
ws.cell(row=row_idx, column=col_idx, value=value)
filepath = os.path.join(OUTPUT_DIR, filename)
wb.save(filepath)
return f"ファイルを作成しました: {filepath}"
@mcp.tool()
def read_excel(filepath: str, sheet_name: str = None) -> dict:
"""
Excelファイルを読み込みます。
Args:
filepath: ファイルパス
sheet_name: シート名(省略時は最初のシート)
Returns:
シートのデータ
"""
if not os.path.isabs(filepath):
filepath = os.path.join(OUTPUT_DIR, filepath)
wb = load_workbook(filepath, data_only=True)
ws = wb[sheet_name] if sheet_name else wb.active
data = []
for row in ws.iter_rows():
data.append([cell.value for cell in row])
return {
"sheet_name": ws.title,
"data": data,
"row_count": len(data),
"col_count": len(data[0]) if data else 0
}
@mcp.tool()
def write_cell(filepath: str, cell: str, value: str, sheet_name: str = None) -> str:
"""
Excelファイルの特定セルに書き込みます。
Args:
filepath: ファイルパス
cell: セル位置(例: "A1", "B2")
value: 書き込む値
sheet_name: シート名(省略時は最初のシート)
Returns:
結果メッセージ
"""
if not os.path.isabs(filepath):
filepath = os.path.join(OUTPUT_DIR, filepath)
wb = load_workbook(filepath)
ws = wb[sheet_name] if sheet_name else wb.active
ws[cell] = value
wb.save(filepath)
return f"セル {cell} に '{value}' を書き込みました"
@mcp.tool()
def write_range(filepath: str, start_cell: str, data: list[list[str]], sheet_name: str = None) -> str:
"""
Excelファイルの範囲に書き込みます。
Args:
filepath: ファイルパス
start_cell: 開始セル(例: "A1")
data: 2次元配列のデータ
sheet_name: シート名(省略時は最初のシート)
Returns:
結果メッセージ
"""
if not os.path.isabs(filepath):
filepath = os.path.join(OUTPUT_DIR, filepath)
wb = load_workbook(filepath)
ws = wb[sheet_name] if sheet_name else wb.active
from openpyxl.utils import coordinate_from_string, column_index_from_string
col_letter, start_row = coordinate_from_string(start_cell)
start_col = column_index_from_string(col_letter)
for row_idx, row in enumerate(data):
for col_idx, value in enumerate(row):
ws.cell(row=start_row + row_idx, column=start_col + col_idx, value=value)
wb.save(filepath)
return f"{start_cell}から{len(data)}行x{len(data[0]) if data else 0}列を書き込みました"
@mcp.tool()
def list_sheets(filepath: str) -> list[str]:
"""
Excelファイルのシート一覧を取得します。
Args:
filepath: ファイルパス
Returns:
シート名のリスト
"""
if not os.path.isabs(filepath):
filepath = os.path.join(OUTPUT_DIR, filepath)
wb = load_workbook(filepath)
return wb.sheetnames
@mcp.tool()
def add_sheet(filepath: str, sheet_name: str) -> str:
"""
Excelファイルに新しいシートを追加します。
Args:
filepath: ファイルパス
sheet_name: 新しいシート名
Returns:
結果メッセージ
"""
if not os.path.isabs(filepath):
filepath = os.path.join(OUTPUT_DIR, filepath)
wb = load_workbook(filepath)
wb.create_sheet(sheet_name)
wb.save(filepath)
return f"シート '{sheet_name}' を追加しました"
@mcp.tool()
def list_files() -> list[str]:
"""
出力ディレクトリのExcelファイル一覧を取得します。
Returns:
ファイル名のリスト
"""
files = [f for f in os.listdir(OUTPUT_DIR) if f.endswith(('.xlsx', '.xls'))]
return files
if __name__ == "__main__":
mcp.run(transport="streamable-http")
Step 3: 依存関係ファイルの作成
requirements.txt を作成します。
mcp[cli]>=1.0.0
openpyxl>=3.1.0
Step 4: 環境構築と起動
# 仮想環境の作成
python3 -m venv venv
# 仮想環境の有効化
source venv/bin/activate # Windows: venv\Scripts\activate
# 依存関係のインストール
pip install -r requirements.txt
# サーバー起動
python server.py
起動すると以下のように表示されます:
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Difyでの設定
Step 1: MCPサーバーの登録
- ブラウザで
http://localhostにアクセス(Difyの管理画面) - 上部メニューから ツール をクリック
- MCP タブを選択
- MCPサーバー(HTTP)を追加 をクリック
- 以下を入力:
| 項目 | 値 |
|---|---|
| サーバーURL | http://host.docker.internal:8000/mcp |
| 名前 | Excel操作 |
| サーバー識別子 | excel-mcp |
- 保存 をクリック
重要: localhost ではなく host.docker.internal を使用してください。
これはDockerコンテナからホストPCにアクセスするためのホスト名です。
Step 2: 接続確認
「認証済み」と表示され、7個のツールが認識されればOKです。
使い方
ワークフローでの使用
- スタジオで新規ワークフローを作成
- + → ツール をクリック
- MCP タブから Excel操作 を選択
- 使いたいツールを選択(例:
create_excel)
テスト例:Excelファイル作成
| パラメータ | 値 |
|---|---|
| filename | test.xlsx |
| data | [["名前", "年齢"], ["太郎", "25"], ["花子", "30"]] |
| sheet_name | Sheet1 |
テスト実行すると ~/Documents/DifyExcel/test.xlsx にファイルが作成されます。
利用可能なツール一覧
| ツール名 | 説明 |
|---|---|
create_excel |
新規Excelファイル作成 |
read_excel |
Excelファイル読み込み |
write_cell |
特定セルに書き込み |
write_range |
範囲に書き込み |
list_sheets |
シート一覧取得 |
add_sheet |
シート追加 |
list_files |
ファイル一覧取得 |
トラブルシューティング
接続できない場合
- MCPサーバーが起動しているか確認
curl http://localhost:8000/mcp
- Difyの設定で
host.docker.internalを使用しているか確認
ファイルが作成されない場合
- 出力ディレクトリ
~/Documents/DifyExcelが存在するか確認 - MCPサーバーのログでエラーを確認
注意事項
- MCPサーバーはDifyを使用する間、起動したままにしてください
- Excelファイルは
~/Documents/DifyExcelに保存されます - Difyのサンドボックス制限を回避するため、MCPサーバー経由でopenpyxlを実行しています
まとめ
MCPサーバーを使うことで、Difyのワークフローからローカル環境のExcelファイルを自由に操作できるようになりました。
この仕組みを応用すれば、Excel以外にも様々なローカルリソースへのアクセスが可能になります。ぜひ活用してみてください!