0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DifyとOutlineをMCP(SSE)でつないでチャットボットにドキュメントを読んでもらう

Last updated at Posted at 2025-04-19

はじめに

技術チャレンジ部のとも(Tomo)です。
以前作った、DifyとDiscordやSlackをつなぐチャットボットに、ナレッジを持たせたい!と思い、DifyでRAGを色々試していましたが、チャンク分割と検索というアプローチがうまくマッチしないケースもあると感じていました。
技術チャレンジ部では、ブラウザのみでwikiのように使えるOutlineに、VR活動で訪問したVRChatワールドの情報などを蓄えていました。
OutlineにはAPIもあり、世の中のコンテキストウィンドウの拡大も著しく、これを丸ごと読ませられれば、またRAGとは異なる結果になるのでは…?
そこで今回は、Outlineをナレッジとして活用できるか、チャレンジします。

ご注意

いずれも執筆時点で「試してみた」レベルの記事となっています。
日々進化している領域で、自分の理解が追いついていない部分があります。
特にセキュリティにはご注意ください。

元の環境

  • Ubuntu 22.04 Server
    • Docker Engine上で動作する、セルフホストのDify
    • Docker Engine上で動作する、セルフホストのOutline
    • DiscordやSlackとDifyをつなぐ、自作Pythonスクリプトのチャットボット

全体設計

世の中MCPが話題なので、チャットボット <-> Dify <-> MCP <-> Outline という構成を検討します。
OutlineでMCPを使えないかと調べたところ、いくつか実装があるようです(未比較)。

他にも、MCPを集約して利用するようなサービスがいくつかあるかと思います(未調査)。
元環境がセルフホストということもあり、試しにmcp-outlineを使ってみます。

mcp-outline

インストール

uv

READMEのInstallationを読むと、uvを使うようです。
今回は、uvのInstallationの最初にある、curlでインストールしてみます。

curl -LsSf https://astral.sh/uv/install.sh | sh

uvでvenvを作れるということで、作ってみます。

uv venv mcp-outline-venv
source mcp-outline-venv/bin/activate
cd mcp-outline-venv

mcp-outline

READMEのInstallationの通りに行います。

git clone https://github.com/Vortiago/mcp-outline.git
cd mcp-outline
uv pip install -e ".[dev]"

設定

READMEのConfigurationの通り、.envにOutlineのAPIキーとURLを設定します。

  • OUTLINE_API_KEY: 設定 -> アカウント -> APIキー -> (画面右上の)新しいAPIキー… で生成
  • OUTLINE_API_URL: http://localhost:3000など

起動

早速動かそうとしましたが、MCPに無知すぎて、何を行えばよいか、全くわかりません。
READMEのInstallationには、mcp dev src/mcp_outline/server.pyと、./start_server.shがあり、どういう関係かわかりません。Dify側も、どうすればいいか、わかりません。
MCPのことを理解するのも目的の1つなので、tcpdumpなども活用しながら、理解を進めました。

MCPの調査

試行錯誤で理解したのは、以下のような点です。
(無知すぎて、間違っているかも&明日には世の中が変わっているかも、すいません)

  • MCPには、現状、stdioSSEがある
    • stdioは、標準入出力を使う
    • SSEは、Server-Sent Eventsを使う (Dify APIでSSEに少し触れていてよかった…)
    • 認証は、MCPの2025-03-26の仕様で規定されたが、まだサポートされていない実装もありそう
  • MCP Inspectorという、ブラウザからMCPの動作を確認できるツールがある
    • mcp-outlineでは、mcp dev src/mcp_outline/server.pyで起動できる
    • 起動すると、MCP Inspector client UI(MCPI)とMCP Proxy(MCPP)がそれぞれ起動する
      • MCPIは、起動時のコンソールログより、http://127.0.0.1:6274でアクセスできる (アドレスの変え方はわからない)
      • MCPPは、6277でアクセスできるが、MCPプロセスと通信できてしまうので、セキュリティ的に公開しないほうがよい (と書かれているが、ssで調べると、6277はデフォルトでは*でlistenしている)
  • mcp-outlineの実装は、ClaudeとWSL2環境でのstdioが想定されている

MCP Inspectorの使用

起動

venvを有効化し、MCP Inspectorを起動します。

source .venv/bin/activate
mcp dev src/mcp_outline/server.py

なお、起動しても、コンソールには何も表示されません。

sshポートフォワーディング

MCP Inspector client UIはhttp://127.0.0.1:6274でアクセスできますが、リモートでホストするため、ブラウザの動く手元のPCからsshでポートフォワーディングします。

ssh -L 6274:localhost:6274 remotehost -N

ブラウザからの接続

ブラウザでhttp://localhost:6274に接続します。

stdioでの使用 (あまり試せていません)

(画面左下の)Connectボタンを押せばすぐ使える…と思いましたが、当方ポンコツのため色々ひっかかりました。
結果として、以下の設定が必要でした。

  • Arguments -> Configuration -> Inspector Proxy Address に、httpで始まるMCPPのURL(http://localhost:6277など)を入力する
    • MCPIからアクセスするURLのはずなので、localhostなどでも大丈夫
  • (必要に応じて)環境変数を追加する

Connecting to MCP Inspector Proxyエラー

Connectボタンを押すと、画面左下にError Connecting to MCP Inspector Proxy - Check Console logsと出たので、試行錯誤しました。
結果として、Arguments -> Configuration -> Inspector Proxy Address には、http://remotehost:6277など、MCPPのアドレスをhttp://から入力する必要があるようです。

uvのVIRTUAL_ENVエラー

これでConnectできるかと思いきや、画面左下に

warning: `VIRTUAL_ENV=/home/tomo/mcp-outline-venv` does not match the project environment path `.venv` and will be ignored; use `--active` to target the active environment instead

といったエラーが出続けました。軽く調べた範囲では、UV_PROJECT_ENVIRONMENTと、VIRTUAL_ENVが一致していれば、回避できるようです。

Arguments -> Environment Variables -> Add Environment Variable で環境変数を追加し、UV_PROJECT_ENVIRONMENTVIRTUAL_ENVの内容(フルパス)を書いてみます。(最適解でない可能性あり)

接続後

接続すると、

  • Command: uv
  • Arguments: run --with mcp mcp run src/mcp_outline/server.py

が、それぞれ入力されていました。これで色々実験できそうです。

SSEでの使用

SSEサーバーの起動

mcp-outlineをSSEに対応させるために、src/mcp_outline/server.pymcp.run()を、mcp.run(transport="sse")に書き換えた後、SSEサーバーを起動します。

source .venv/bin/activate
bash ./start_server.sh

設定

  • stdioと同じように、Arguments -> Configuration -> Inspector Proxy Address に、httpで始まるMCPPのURL(http://localhost:6277など)を入力
  • (画面左上の)URLに、SSEサーバーのアドレス(デフォルトではhttp://localhost:8000/sseでアクセスできるはず)を入力

これでConnectできるようになりました。

settings.png

MCP InspectorによるOutlineの挙動確認

LLMの気持ちになって(?)MCP InspectorでOutlineの挙動の確認することで、LLMからOutlineがどう見えるのか、よくわかりました。
この理解が、後々のLLMのプロンプト改善に役立ちました。

MCP Inspectorの操作

詳細は本家に譲りますが、下記を試してみました。

  • (画面上の)Tools -> List Tools で、Toolの一覧が取得できる
    • 取得後、一覧にある各Toolをクリックすることで、Toolを呼び出せる
    • 呼び出した結果は(画面右の)Tool Resultに表示され、JSONは(画面下の)Historyにtool/callとして格納されるので、展開して見られる
      • HistoryのResponse内の長い文字列は折りたたまれているので、クリックで展開して見られる
  • Historyは、新しい操作が上になる模様

MCPで呼び出せるOutlineの挙動

気になった挙動をいくつかピックアップします。

  • 呼び出せるToolの説明が(英語で)取得できる
  • コレクション(Outlineの大分類)の一覧が取得できる
    • コレクションのタイトルだけでなく、コレクションに直接書かれた内容も取得できる
    • コレクション配下のドキュメント一覧は、コレクション一覧には入ってこない
      • コレクションのIDを指定すれば、ドキュメントの一覧を取得できる
  • 検索機能がある

基本はOutlineのAPIそのものかと思います。LLMは、自然言語の説明を読んでToolを活用するというわけですね。

MCP Inspectorではこんな感じで見られます。

  • Tools
    • tools.png
  • History
    • history.png

Difyからの呼び出し

ここまででmcp-outlineが動かせるようになりました。MCP Inspectorを停止し、DifyからMCPで接続します。
Difyでは、マーケットプレースにてMCP SSEMCP Agent Strategyがプラグインとしてインストールできるようです。
いずれもlanggeniusによるものではなさそうですが、dify.aiのblogで紹介されていました。また、SSEに対応しているようです。
今回はチャットフローで使いたいので、MCP Agent Strategyを使ってみます。
mcp-outlineは、SSEで使用するので、start_server.shでSSEサーバーを起動しておきます。

MCP Agent Strategyのインストール

(画面右上の)プラグイン -> (画面左上の)マーケットプレイスを探索する -> (画面中の)エージェント戦略 で、MCP Agent Strategyをインストールします。

DockerのDifyからホスト上のサービスへの接続

元々、DifyのDockerコンテナからホスト上のサービスに接続できるように、Difyのdocker-compose.override.yamlextra_hosts:- "host.docker.internal:host-gateway"を設定していました。これをこのまま利用します。
docker-compose.override.yamlでは、apiplugin_daemonserviceに対して、host.docker.internalを設定していました。(どちらが必須かなど、詳細未調査)

チャットフロー

エージェントノードを追加し、以下のように設定してみました。

  • エージェンティック戦略: MCP Agent -> MCP FunctionCall を設定
  • MCP Server URL: { "outline": { "url": "{{#env.mcp_url#}}", "headers": {}, "timeout": 60, "sse_read_timeout": 300 }}
    • (画面右上の)ENVで、環境変数mcp_urlに、エンドポイントも含むhttp://host.docker.internal:8000/sseを設定
  • Maximum Iterations: デフォルトの3では少なそうなので、とりあえず5を設定

実行と解析

これでついに質問ができる! と思い、DifyのプレビューでOutlineに含まれていそうな情報の質問をしてみます。…が、微妙な回答…。

Difyでの解析

Difyの会話ログ -> 実行追跡 -> エージェント(ノードの名前) -> function calling -> 詳細情報 で、エージェントの各Roundの挙動をJSONレベルで確認します。
すると、LLMがまずOutlineの検索機能でキーワード検索し、検索にかからなかったのであきらめたりしている様子が見えました。

Outline

LLMの気持ちになって、Outlineの画面で単語を入れて色々検索してみます。
うーん、確かにこれは厳しいかも…。

改善

Outlineのドキュメント構造

MCP Inspectorでの確認で、Outlineのコレクション一覧を取得する際に、コレクションに直接書かれた内容も取得できることがわかっています。
そこで、コレクションのトップ階層に、目次として、各ドキュメントにどんなことが書いてあるか、ドキュメントへのリンクとセットで記述しておきます。リンクには、ドキュメントのIDが入っているので、該当ドキュメントを取得してくれると期待します。

collection.png

DifyのLLMプロンプト

Maximum Iterationsが5回だと、検索などを試しているうちに、最大回数に近づいてしまいそうです。
そこで、Maximum Iterationsを8回にしつつ、エージェントノードのInstructionのプロンプトで、

ドキュメントの調査は、Outlineの検索機能は使わず、コレクションリストの内容から関連しそうなドキュメントIDを探し出す方法で行い、そのIDのドキュメント内容を取得・解釈した上で回答して下さい

などと指定してみます。

SSEサーバーのlistenアドレス変更

SSEサーバーのlistenアドレスをssで確認すると、0.0.0.0:8000になっていました。
気分レベルの対処ですが、Docker内部からhost.docker.internalで解決されるデフォルトブリッジのアドレスに変えてみます。
ip addr show dev docker0で見ると、この環境でのアドレスはデフォルトの172.17.0.1のようです。
変え方がわからなかったのですが、MCP Python SDKのfastmcpのserver.pyのコードを読むと、FASTMCP_HOSTという環境変数で設定できそうだったので、.envFASTMCP_HOST="172.17.0.1"を追記したところ、効果がありました。

SSEサーバーのsystemd --user化

SSEサーバーをsystemd --userで管理するために、.serviceファイルを設置しました。(内容は適当です)

~/.config/systemd/user/mcp-outline.service
[Unit]
Description=mcp sse server for outline
After=network.target

[Service]
WorkingDirectory=/home/tomo/mcp-outline-venv/mcp-outline
ExecStart=bash start_server.sh
Restart=always
Environment="PYTHONUNBUFFERED=1"

[Install]
WantedBy=default.target

その後、起動・確認しました。

systemd --user daemon-reload
systemd --user enable --now mcp-outline.service
systemd --user status mcp-outline.service

ユーザーがログアウトしても動き続けるように、だいぶ前に、lingeringを有効にしていた…と思われる…。

sudo loginctl enable-linger $(USER)

改めて実行

discord.png

やったね!

感想

未知の世界で、AI自身のMCP関連知識もまだ少なめの模様、自分の中で総力戦でした。
組織でのナレッジ活用に向けて、情報の単位の切れ目をどう表現するか、コンテキストウィンドウとコストにどう合わせるか、それをどうLLMに伝えるか、その結果をどうキャッシュするかなど、今後進化があるかもと思いました。
LLM側の進化で、LLMが既存の情報構造に歩み寄ってくれるかもですが…。

課題と今後

  • mcp-outline
    • 再起動や停止に時間がかかる: グレースフルな終了には対処が必要そう
    • セキュリティ: MCP Python SDKの認証の実装進展に期待(自分でやりましょう>私)
  • Outline
    • APIキーへのパーミッション: 詳細を調べて、適切なパーミッションにしたい
      • 今は自然言語で「変更しないでね」とLLMにお願い…指示追従性は高まっているそうですが、AIなので…
  • Dify
    • (チャットフローではなく)エージェントで作る場合: プラグインと挙動の調査
  • 技術チャレンジ部でのユースケース
    • VR活動: VRChatの訪問先を自動的にデータベース化したい!(お気に入りがもういっぱいで…)
    • 自動運転AIチャレンジ: GitHubのソースコードも見て欲しい!

謝辞

  • VR活動の記録を残し続けていただいている、たけさん、いつも本当にありがとうございます!
  • 多数の記事に助けられました! ありがとうございます!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?