Dify×MCPを試してみた① Zapier編
こんにちは、田中です。
今日のビジネス環境において、外部データソースをAPI経由で連携させる必要性はますます高まっています。しかし、これらのAPI連携を個別に実装し、連携ロジックをコードで管理するのは、開発工数、エラーハンドリング、メンテナンス性の観点から大きな負担となり得ます。
ここで注目されるのが、Managed Content/Capability Platform (MCP) という概念です。本記事では、このMCPがなぜ重要なのか、そしてLLMアプリケーション開発プラットフォームDifyとMCPを組み合わせることで、特に複数のAPI連携を伴う複雑なワークフローをいかに効率的に構築・管理できるようになるかを解説していきます。
MCPとは
MCPは、単なるコンテンツ管理システム(CMS)やナレッジベースを超えた概念です。LLMやエージェントが必要とする以下の二つの要素を一元的に管理し、制御された形で提供するためのプラットフォーム基盤と捉えることができます。
- コンテンツ (Content): 社内ドキュメント、データベース、Webサイトなど、LLMが参照・学習するための情報源。
- 機能・能力 (Capability): 外部APIの呼び出し、特定機能の実行、SaaSツールの操作など、LLMが現実世界に働きかけるための「ツール」。
MCPは、これらのコンテンツやツールへのアクセスを集約・抽象化し、LLMアプリケーション(例えばDifyで構築されたもの)に対して、管理・統制されたインターフェースを提供します。これにより、セキュリティの確保、アクセス制御、利用状況の監視、ツールの追加・更新の容易化といったメリットが生まれます。「MCPサーバー」として機能し、様々なツールやプラットフォーム間の連携を仲介するハブとなるイメージです。
Dify × MCP連携の真価:API連携における違い
Difyは単体でも、カスタムツールとしてAPIを登録し、ワークフロー内で利用する機能を持ちます。しかし、扱うAPIの種類や数が増え、連携ロジックが複雑化するにつれて、以下のような課題が生じやすいです。
- ツール管理の煩雑化: 個々のAPIの仕様変更への追従、認証情報の管理、利用権限の設定などが個別に発生し、管理コストが増大する。
- 再利用性の低下: 特定のワークフローのためだけにAPIツールを定義すると、他のワークフローでの再利用が難しい場合がある。
- ガバナンスの欠如: 誰がどのAPIをどの程度の頻度で利用しているか、といった全体的な利用状況の把握や統制が難しい。
ここでMCPが真価を発揮します。Dify公式ブログでも紹介されているように、例えばZapierのようなAPI連携プラットフォームをMCPプラグイン経由でDifyに統合できます。これによりZapierに登録した多くのAPIからAIが自律的に用途に合ったAPIを選別して、指示を実行してくれます。
これは何を意味するのでしょうか? DifyはZapierと連携することで、個別のAPI設定をすることなく、Zapier経由で多様な外部サービスを操作できるようになります。
デモ
Dify×MCPの例で特に威力を発揮するケースが複数のAPI連携を行う際です。
ここではGoogle calendarで得た予定をGmailを使って送信するアプリをDifyとZapierというMCPサーバーを用いて作っていきます。
手順:
-
まずはこちらからZapierのアカウントを作ります。
-
アクセスしたサイトからGet startedを選択します。
-
Googleアカウントなどから作成します。
-
作成するアカウントを選択したのちに以下のような質問が出てくるので答えていきます。
-
質問に答え終わると以下のようなページになるのでSettingsのMCPを選択してください。
-
以下のページになったらGenerate URLを選択してください。
-
URLが作成されたらCopy URLを選択してください。
※このURLを用いることでZapierをdifyなどの外部AIツールと連携させることができます。
-
次にQuick Startの2.からConfigure the actionをクリックしてください。
-
アクセスしたページのAdd a new actionを選択してください。
-
Actionにdifyと連携させたいアプリを設定します。
※今回の場合はGoogle Calendar とGmailです。
-
まずはActionにGoogle Calendar: Find eventを設定します。
-
次に連携させるGoogle CalendarのGoogleアカウントを設定するためにConnect a new Google Calendar accountを選択し、アカウントを選択します。
-
その後出てきたCalendarという項目において、Set a specific value for this fieldを選択します。
-
その下の欄に使用するCalendarのGoogleアカウントを設定する
-
Enable Actionを選択します。
※これでGoogle Calendarから予定を見つけるというアクションは登録されました。 -
次に同じようにGmailを送るアクションを登録するためにAdd a new actionを選択します。
-
Action からGmail:Send Emailを選択します。
-
次にCalendarと同様にGmail accountから送信主にしたいアカウントを選択します。
-
To, Subject, Body においてHave AI guess a value for this field を選択します。
-
Enable actionを選択します。
※これでZapierの設定は完了となります。
-
次にDifyにログインします。
※アカウントがない方は作ってください。
-
アプリを作成する→最初から作成するを選択します。
-
アプリの種類→チャットフローとする。
アプリのアイコンと名前はなんでもよい。
-
その後作成するを選択する。
-
LLMを削除します。
-
開始のブロックのプラスボタンを選択してエージェントを選択します。
-
エージェントノードのプラスボタンからもう一つエージェントノードを追加します。
-
二つ目のエージェントノード(エージェント2)の+ボタンから線を引っ張り、回答ブロックと接続します。
-
回答ブロックの応答にはLLMブロック/textが指定されているので削除して、エージェント2/textを指定します。
-
次にエージェントのエージェンティック戦略をMCP AgentのMCP Function Callingにします。
※まだMCP Agentをインストールしていない場合は以下の手順でMCP Agentをインストールしてください。
-
「マーケットプレイスでさらに見つけてください」を選択します。
-
MCP Agent Strategyを選択します。
-
インストールします。
-
-
Modelを選択する。
※なんでもよいです。
-
Tools Listは
Current Time→Current Time
Current Time→Weekday Calculator を選択します。
-
Current Timeにおいては設定からTimezoneをTokyoにしてください。
-
次に右上のENVと書かれているボタンを押し、環境変数を設定します。
-
環境変数の追加から
タイプはString
変数名はなんでもよい
値にはZapierからコピーしたURLを張り付けます。
-
エージェントのMCP SERVER URLに先ほど設定した変数を設定します。
-
Instructionには以下のものコピペします。
Userの指示に従い適切なツールを使用してください。 今日の日付を取得する際には、CurrentTimeを使ってください。 昨日や明日や明後日などの日付を取得する際にはCurrentTimeから計算を行い取得してください。 曜日について指示があった際にはWeekday Calculatorを用いて計算してください。 予定について尋ねられた際にはzapier_mcpから得られるGoogle Calendar情報を用いて予定を取得してください。 日付を指定されている場合その日以外の予定は送信しないでください。 予定についてはカレンダーに書いている情報以外は書かないでください。 送信は行わなくてよいです。 出力は質問内容への解答だけでいいです。
-
QUERYにはsys.queryを選択します。
-
今度はエージェント2について設定を行います。
設定に関しては以下の値をそれぞれ入れます。
※instructionについては後述
※QUERYのところはエージェント/textが入っていることに注意
-
エージェント2のinstructionについては以下のように入力してください
送信してと言われたらエージェント/textをそのままGmailを使って指定された宛先に送信してください。 許可を取る必要はないです。
-
右上の公開を押す。
-
アプリを実行を選択する。
-
チャットに依頼内容を打ち込むと以下のようになります。
-
送られたメールは以下のようになります。
実際のDSLファイルはこのようになります
app:
description: ''
icon: 🤖
icon_background: '#FFEAD5'
mode: advanced-chat
name: mcp_demo
use_icon_as_answer_icon: false
dependencies: []
kind: app
version: 0.2.0
workflow:
conversation_variables: []
environment_variables:
- description: ''
id: 7ac3986c-cb91-4fe5-a807-884755e0b871
name: MCP_Zapier
selector:
- env
- MCP_Zapier
value: https://actions.zapier.com/mcp/sk-ak-BwksCWdZ9W0ng10pHIkNJBRzOx/sse
value_type: string
features:
file_upload:
allowed_file_extensions:
- .JPG
- .JPEG
- .PNG
- .GIF
- .WEBP
- .SVG
allowed_file_types:
- image
allowed_file_upload_methods:
- local_file
- remote_url
enabled: false
fileUploadConfig:
audio_file_size_limit: 50
batch_count_limit: 5
file_size_limit: 15
image_file_size_limit: 10
video_file_size_limit: 100
workflow_file_upload_limit: 10
image:
enabled: false
number_limits: 3
transfer_methods:
- local_file
- remote_url
number_limits: 3
opening_statement: ''
retriever_resource:
enabled: true
sensitive_word_avoidance:
enabled: false
speech_to_text:
enabled: false
suggested_questions: []
suggested_questions_after_answer:
enabled: false
text_to_speech:
enabled: false
language: ''
voice: ''
graph:
edges:
- data:
isInIteration: false
isInLoop: false
sourceType: start
targetType: agent
id: 1745052852509-source-1745053053196-target
source: '1745052852509'
sourceHandle: source
target: '1745053053196'
targetHandle: target
type: custom
zIndex: 0
- data:
isInIteration: false
isInLoop: false
sourceType: agent
targetType: agent
id: 1745053053196-source-1745058131075-target
source: '1745053053196'
sourceHandle: source
target: '1745058131075'
targetHandle: target
type: custom
zIndex: 0
- data:
isInLoop: false
sourceType: agent
targetType: answer
id: 1745058131075-source-answer-target
source: '1745058131075'
sourceHandle: source
target: answer
targetHandle: target
type: custom
zIndex: 0
nodes:
- data:
desc: ''
selected: false
title: 開始
type: start
variables: []
height: 54
id: '1745052852509'
position:
x: 80
y: 282
positionAbsolute:
x: 80
y: 282
sourcePosition: right
targetPosition: left
type: custom
width: 244
- data:
answer: '{{#1745058131075.text#}}'
desc: ''
selected: false
title: 回答
type: answer
variables: []
height: 104
id: answer
position:
x: 1038.3030083212543
y: 288.00507835175284
positionAbsolute:
x: 1038.3030083212543
y: 288.00507835175284
selected: false
sourcePosition: right
targetPosition: left
type: custom
width: 244
- data:
agent_parameters:
instruction:
type: constant
value: 'Userの指示に従い適切なツールを使用してください
今日の日付を取得する際には、CurrentTimeを使ってください。
昨日や明日や明後日などの日付を取得する際にはCurrentTimeから計算を行い取得してください.
曜日について指示があった際にはWeekday Calculatorを用いて計算してください
予定について尋ねられた際にはzapier_mcpから得られるGoogle Calender情報を用いて予定を取得してください。
日付を指定されている場合その日以外の予定は送信しないでください
予定についてはカレンダーに書いている情報以外は書かないでください
送信は行わなくてよいです
出力は質問内容への解答だけでいいです'
mcp_server:
type: constant
value: '{{#env.MCP_Zapier#}}'
model:
type: constant
value:
completion_params: {}
mode: chat
model: gemini-2.0-flash
model_type: llm
provider: langgenius/gemini/google
type: model-selector
query:
type: constant
value: '{{#sys.query#}}'
tools:
type: constant
value:
- enabled: true
extra:
description: ''
parameters: {}
provider_name: time
schemas:
- auto_generate: null
default: '%Y-%m-%d %H:%M:%S'
form: form
human_description:
en_US: Time format in strftime standard.
ja_JP: Time format in strftime standard.
pt_BR: Time format in strftime standard.
zh_Hans: strftime 标准的时间格式。
label:
en_US: Format
ja_JP: Format
pt_BR: Format
zh_Hans: 格式
llm_description: null
max: null
min: null
name: format
options: []
placeholder: null
precision: null
required: false
scope: null
template: null
type: string
- auto_generate: null
default: UTC
form: form
human_description:
en_US: Timezone
ja_JP: Timezone
pt_BR: Timezone
zh_Hans: 时区
label:
en_US: Timezone
ja_JP: Timezone
pt_BR: Timezone
zh_Hans: 时区
llm_description: null
max: null
min: null
name: timezone
options:
- label:
en_US: UTC
ja_JP: UTC
pt_BR: UTC
zh_Hans: UTC
value: UTC
- label:
en_US: America/New_York
ja_JP: America/New_York
pt_BR: America/New_York
zh_Hans: 美洲/纽约
value: America/New_York
- label:
en_US: America/Los_Angeles
ja_JP: America/Los_Angeles
pt_BR: America/Los_Angeles
zh_Hans: 美洲/洛杉矶
value: America/Los_Angeles
- label:
en_US: America/Chicago
ja_JP: America/Chicago
pt_BR: America/Chicago
zh_Hans: 美洲/芝加哥
value: America/Chicago
- label:
en_US: America/Sao_Paulo
ja_JP: America/Sao_Paulo
pt_BR: América/São Paulo
zh_Hans: 美洲/圣保罗
value: America/Sao_Paulo
- label:
en_US: Asia/Shanghai
ja_JP: Asia/Shanghai
pt_BR: Asia/Shanghai
zh_Hans: 亚洲/上海
value: Asia/Shanghai
- label:
en_US: Asia/Ho_Chi_Minh
ja_JP: Asia/Ho_Chi_Minh
pt_BR: Ásia/Ho Chi Minh
zh_Hans: 亚洲/胡志明市
value: Asia/Ho_Chi_Minh
- label:
en_US: Asia/Tokyo
ja_JP: Asia/Tokyo
pt_BR: Asia/Tokyo
zh_Hans: 亚洲/东京
value: Asia/Tokyo
- label:
en_US: Asia/Dubai
ja_JP: Asia/Dubai
pt_BR: Asia/Dubai
zh_Hans: 亚洲/迪拜
value: Asia/Dubai
- label:
en_US: Asia/Kolkata
ja_JP: Asia/Kolkata
pt_BR: Asia/Kolkata
zh_Hans: 亚洲/加尔各答
value: Asia/Kolkata
- label:
en_US: Asia/Seoul
ja_JP: Asia/Seoul
pt_BR: Asia/Seoul
zh_Hans: 亚洲/首尔
value: Asia/Seoul
- label:
en_US: Asia/Singapore
ja_JP: Asia/Singapore
pt_BR: Asia/Singapore
zh_Hans: 亚洲/新加坡
value: Asia/Singapore
- label:
en_US: Europe/London
ja_JP: Europe/London
pt_BR: Europe/London
zh_Hans: 欧洲/伦敦
value: Europe/London
- label:
en_US: Europe/Berlin
ja_JP: Europe/Berlin
pt_BR: Europe/Berlin
zh_Hans: 欧洲/柏林
value: Europe/Berlin
- label:
en_US: Europe/Moscow
ja_JP: Europe/Moscow
pt_BR: Europe/Moscow
zh_Hans: 欧洲/莫斯科
value: Europe/Moscow
- label:
en_US: Australia/Sydney
ja_JP: Australia/Sydney
pt_BR: Australia/Sydney
zh_Hans: 澳大利亚/悉尼
value: Australia/Sydney
- label:
en_US: Pacific/Auckland
ja_JP: Pacific/Auckland
pt_BR: Pacific/Auckland
zh_Hans: 太平洋/奥克兰
value: Pacific/Auckland
- label:
en_US: Africa/Cairo
ja_JP: Africa/Cairo
pt_BR: Africa/Cairo
zh_Hans: 非洲/开罗
value: Africa/Cairo
placeholder: null
precision: null
required: false
scope: null
template: null
type: select
settings:
format:
value: '%Y-%m-%d %H:%M:%S'
timezone:
value: Asia/Tokyo
tool_label: Current Time
tool_name: current_time
type: builtin
- enabled: true
extra:
description: ''
parameters:
day:
auto: 1
value: null
month:
auto: 1
value: null
year:
auto: 1
value: null
provider_name: time
schemas:
- auto_generate: null
default: null
form: llm
human_description:
en_US: Year
ja_JP: Year
pt_BR: Year
zh_Hans: 年
label:
en_US: Year
ja_JP: Year
pt_BR: Year
zh_Hans: 年
llm_description: null
max: null
min: null
name: year
options: []
placeholder: null
precision: null
required: true
scope: null
template: null
type: number
- auto_generate: null
default: null
form: llm
human_description:
en_US: Month
ja_JP: Month
pt_BR: Month
zh_Hans: 月
label:
en_US: Month
ja_JP: Month
pt_BR: Month
zh_Hans: 月
llm_description: null
max: null
min: null
name: month
options: []
placeholder: null
precision: null
required: true
scope: null
template: null
type: number
- auto_generate: null
default: null
form: llm
human_description:
en_US: day
ja_JP: day
pt_BR: day
zh_Hans: 日
label:
en_US: day
ja_JP: day
pt_BR: day
zh_Hans: 日
llm_description: null
max: null
min: null
name: day
options: []
placeholder: null
precision: null
required: true
scope: null
template: null
type: number
settings: {}
tool_label: Weekday Calculator
tool_name: weekday
type: builtin
agent_strategy_label: MCP FunctionCalling
agent_strategy_name: function_calling
agent_strategy_provider_name: hjlarry/agent/mcp_agent
desc: ''
output_schema: null
plugin_unique_identifier: hjlarry/agent:0.0.1@f42a5a80b1c77fd0655c755b70ad08da47ceb1acc3638cf13a0eb9ed42b3a128
selected: false
title: エージェント
type: agent
height: 198
id: '1745053053196'
position:
x: 384
y: 282
positionAbsolute:
x: 384
y: 282
selected: true
sourcePosition: right
targetPosition: left
type: custom
width: 244
- data:
agent_parameters:
instruction:
type: constant
value: '送信してと言われたら{{#1745053053196.text#}}をそのままGmailを使って指定された宛先に送信してください。
許可を取る必要はないです。
出力は日本語にして'
mcp_server:
type: constant
value: '{{#env.MCP_Zapier#}}/'
model:
type: constant
value:
completion_params: {}
mode: chat
model: gemini-2.0-flash
model_type: llm
provider: langgenius/gemini/google
type: model-selector
query:
type: constant
value: '{{#sys.query#}}{{#1745053053196.text#}}'
tools:
type: constant
value:
- enabled: true
extra:
description: ''
parameters: {}
provider_name: time
schemas:
- auto_generate: null
default: '%Y-%m-%d %H:%M:%S'
form: form
human_description:
en_US: Time format in strftime standard.
ja_JP: Time format in strftime standard.
pt_BR: Time format in strftime standard.
zh_Hans: strftime 标准的时间格式。
label:
en_US: Format
ja_JP: Format
pt_BR: Format
zh_Hans: 格式
llm_description: null
max: null
min: null
name: format
options: []
placeholder: null
precision: null
required: false
scope: null
template: null
type: string
- auto_generate: null
default: UTC
form: form
human_description:
en_US: Timezone
ja_JP: Timezone
pt_BR: Timezone
zh_Hans: 时区
label:
en_US: Timezone
ja_JP: Timezone
pt_BR: Timezone
zh_Hans: 时区
llm_description: null
max: null
min: null
name: timezone
options:
- label:
en_US: UTC
ja_JP: UTC
pt_BR: UTC
zh_Hans: UTC
value: UTC
- label:
en_US: America/New_York
ja_JP: America/New_York
pt_BR: America/New_York
zh_Hans: 美洲/纽约
value: America/New_York
- label:
en_US: America/Los_Angeles
ja_JP: America/Los_Angeles
pt_BR: America/Los_Angeles
zh_Hans: 美洲/洛杉矶
value: America/Los_Angeles
- label:
en_US: America/Chicago
ja_JP: America/Chicago
pt_BR: America/Chicago
zh_Hans: 美洲/芝加哥
value: America/Chicago
- label:
en_US: America/Sao_Paulo
ja_JP: America/Sao_Paulo
pt_BR: América/São Paulo
zh_Hans: 美洲/圣保罗
value: America/Sao_Paulo
- label:
en_US: Asia/Shanghai
ja_JP: Asia/Shanghai
pt_BR: Asia/Shanghai
zh_Hans: 亚洲/上海
value: Asia/Shanghai
- label:
en_US: Asia/Ho_Chi_Minh
ja_JP: Asia/Ho_Chi_Minh
pt_BR: Ásia/Ho Chi Minh
zh_Hans: 亚洲/胡志明市
value: Asia/Ho_Chi_Minh
- label:
en_US: Asia/Tokyo
ja_JP: Asia/Tokyo
pt_BR: Asia/Tokyo
zh_Hans: 亚洲/东京
value: Asia/Tokyo
- label:
en_US: Asia/Dubai
ja_JP: Asia/Dubai
pt_BR: Asia/Dubai
zh_Hans: 亚洲/迪拜
value: Asia/Dubai
- label:
en_US: Asia/Kolkata
ja_JP: Asia/Kolkata
pt_BR: Asia/Kolkata
zh_Hans: 亚洲/加尔各答
value: Asia/Kolkata
- label:
en_US: Asia/Seoul
ja_JP: Asia/Seoul
pt_BR: Asia/Seoul
zh_Hans: 亚洲/首尔
value: Asia/Seoul
- label:
en_US: Asia/Singapore
ja_JP: Asia/Singapore
pt_BR: Asia/Singapore
zh_Hans: 亚洲/新加坡
value: Asia/Singapore
- label:
en_US: Europe/London
ja_JP: Europe/London
pt_BR: Europe/London
zh_Hans: 欧洲/伦敦
value: Europe/London
- label:
en_US: Europe/Berlin
ja_JP: Europe/Berlin
pt_BR: Europe/Berlin
zh_Hans: 欧洲/柏林
value: Europe/Berlin
- label:
en_US: Europe/Moscow
ja_JP: Europe/Moscow
pt_BR: Europe/Moscow
zh_Hans: 欧洲/莫斯科
value: Europe/Moscow
- label:
en_US: Australia/Sydney
ja_JP: Australia/Sydney
pt_BR: Australia/Sydney
zh_Hans: 澳大利亚/悉尼
value: Australia/Sydney
- label:
en_US: Pacific/Auckland
ja_JP: Pacific/Auckland
pt_BR: Pacific/Auckland
zh_Hans: 太平洋/奥克兰
value: Pacific/Auckland
- label:
en_US: Africa/Cairo
ja_JP: Africa/Cairo
pt_BR: Africa/Cairo
zh_Hans: 非洲/开罗
value: Africa/Cairo
placeholder: null
precision: null
required: false
scope: null
template: null
type: select
settings:
format:
value: '%Y-%m-%d %H:%M:%S'
timezone:
value: UTC
tool_label: Current Time
tool_name: current_time
type: builtin
agent_strategy_label: MCP FunctionCalling
agent_strategy_name: function_calling
agent_strategy_provider_name: hjlarry/agent/mcp_agent
desc: ''
output_schema: null
plugin_unique_identifier: hjlarry/agent:0.0.1@f42a5a80b1c77fd0655c755b70ad08da47ceb1acc3638cf13a0eb9ed42b3a128
selected: false
title: エージェント 2
type: agent
height: 198
id: '1745058131075'
position:
x: 688
y: 282
positionAbsolute:
x: 688
y: 282
selected: false
sourcePosition: right
targetPosition: left
type: custom
width: 244
viewport:
x: 575.2647921598689
y: 264.84697840196714
zoom: 0.5401478780503224
このようにすることでGmailとGoogleCalendarどちらとも連携することができます。
まとめ:MCPが拓く、自律型エージェントの未来
Dify × MCPの組み合わせは、LLMエージェントに高度な「実行能力」を与え、かつそれを管理・統制するための強力な基盤を提供します。特に、複数のAPI連携を必要とする複雑な業務プロセスを自動化・高度化する上で、その効果は絶大です。
MCPは、LLMアプリケーション開発における、コンテンツと機能の「供給網」を整備する役割を担う。これにより、開発者はより迅速かつ安全に、高機能なエージェントを構築し、ビジネス価値へと繋げることが可能になります。
参考
Discussion