最近は「とりあえず全データをベクトルDBへ投入してRAG化」という構成が多いですが、Redmineのようなチケット管理システムでは、
- チケットが増え続ける
- コメントが大量に存在する
- ベクトル化コストが高い
- 最新情報との同期が必要
という問題があります。(私も何とかDifyで取ってきてRAG化しようと頑張ってみたけどループの制限など色々躓きポイントが多く、チケットが膨大になるとRAG化は厳しいと感じていました)
そこで、
「ナレッジを事前にRAG化するのではなく、LLMにRedmineの検索方法を教え、必要に応じてMCP経由でRedmineを検索させる」
という人間的アプローチはできないかと検索していたところ、なんとMCPでRedmineを操作できるツールを作っておられる方がいらっしゃるではないですか!
MCPを利用することで、RedmineそのものをAIの知識ソース兼業務システムとして利用するAIエージェント としての価値が生まれます。
構成
LLMからは直接MCP Serverと通信せずMCPホストであるOpen-WebUを介してやり取りされます。
利用者
↓↑
Open-WebUI ←→ Ollama
↓↑
(Tool list/Call)
↓↑
Redmine-MCP-Server
↓↑
Redmine
├ チケット
├ コメント
├ Wiki
├ 添付ファイル
├ ガントチャート
└ カスタムフィールド
通信とデータの流れ
- 質問の送信: ユーザーがOpen-WebUIにテキストを入力すると、Open-WebUIがそのリクエストを受け取ります。
- 状況判断: Open-WebUIはLLM(Ollama)にテキストを送り、LLMが「これはどのMCPサーバーのツールを使えば解決できるか」を判断します。
- MCP呼び出し: LLMが特定のツール使用を要求した場合、Open-WebUIはそれを検知し、該当するMCP Serverに対してJSON-RPC(標準通信プロトコル)で処理の実行を命じます。
- 結果の返却: MCP Serverが外部APIやデータベースからデータを取得し、その結果をOpen-WebUIに返します。
- 回答の生成: Open-WebUIは取得したデータをLLM(Ollama)に渡し、LLMがそれらの情報を元に自然言語の回答を作成し、ユーザーに返します。 [1]
構築手順
1. Ollamaとopen-webuiの環境構築
docker-composeで設定します。アクセスは http://127.0.0.1:3000/ です。
mkdir -p ~/work/openwebui/data
mkdir -p ~/work/openwebui/ollama
cd ~/work/openwebui/
vi docker-compose.yml
```yaml
version: "3.9"
services:
open-webui:
image: ghcr.io/open-webui/open-webui
container_name: open-webui
restart: unless-stopped
ports:
- "3000:8080"
volumes:
- ./data:/app/backend/data
ollama:
image: ollama/ollama
container_name: ollama
volumes:
- ./ollama:/root/.ollama
ports:
- "11434:11434"
restart: always
redmine-mcp-server:
build:
context: ./redmine-mcp-server
dockerfile: Dockerfile
container_name: redmine-mcp-server
ports:
- "8000:8000"
env_file:
- ./redmine-mcp-server/.env.docker
volumes:
- ./redmine-mcp-server/logs:/app/logs
- ./redmine-mcp-server/data:/app/data
restart: unless-stopped
networks:
- mcp-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
redmine-mcp-network:
driver: bridge
```
ここではまだ立ち上げません。このあとのredmine-mcp-serverの設定を終えてからとなります。
ollamaが同じホストのホストOS上で立ち上げている場合は、以下を追加しておいて下さい。コンテナや別ホストなら以下設定は不要です。
extra_hosts: - "host.docker.internal:host-gateway"
3. RedmineのAPIアクセスキーの取得
Redmineはすでに動作しているものとします。必要な権限があるアカウントのAPIを取得してください。

4. redmine-mcp-server導入
今回は、「https://github.com/jztan/redmine-mcp-server」を使わせていただきます。
これは、Redmineプロジェクト管理システムと連携するモデルコンテキストプロトコル(MCP)サーバー。このサーバーはMCPツールを介してRedmineデータへのシームレスなアクセスを提供し、AIアシスタントがRedmineインスタンスと連携できるようにします。
特徴
- 45個のMCPツール(加えて、1つのオペレーターツールは制限付き
REDMINE_MCP_EXPOSE_ADMIN_TOOLS=true):課題、プロジェクト、時間追跡、Wiki、ガントチャート、ファイル操作、メンバーシップ管理、製品、連絡先(CRM)、DMSFドキュメントなど - 柔軟な認証方式:APIキー、ユーザー名/パスワード、またはOAuth2ユーザーごとのトークン
- プロンプトインジェクション保護:安全なLLM消費のために境界タグでラップされたユーザー制御コンテンツ
- 読み取り専用モード
REDMINE_MCP_READ_ONLY:環境変数を使用して読み取り専用操作に制限します - HTTPファイル配信:UUIDベースのURLによる安全な添付ファイルアクセスと自動有効期限設定
- ページネーションサポート:設定可能な制限により、大量の結果セットを効率的に処理します。
- MCP準拠:FastMCPとHTTPトランスポートによる完全なモデルコンテキストプロトコルサポート
- Docker対応:完全なコンテナ化サポート
クイックスタート
ここでは、予め作成されたDockerイメージを利用します。
githubからリポジトリをダウンロードし、Docker用の設定ファイル[.env.docker]を設定します。
cd ~/work/openwebui/
git clone https://github.com/jztan/redmine-mcp-server.git
cd redmine-mcp-server/
cp .env.docker.example .env.docker
vi .env.docker
---
<略>
REDMINE_URL=http://[REDMINEサーバのURL]
#REDMINE_USERNAME=your_username ← APIを使うのでコメントアウト
#REDMINE_PASSWORD=your_password ← APIを使うのでコメントアウト
REDMINE_API_KEY=[REDMINEから取得したAPIキー]
REDMINE_AUTH_MODE=legacy
# Server configuration
SERVER_HOST=0.0.0.0
SERVER_PORT=8000
# Public URL configuration for file serving
PUBLIC_HOST=localhost ← MCP-serverを外部からアクセスさせる場合に設定
PUBLIC_PORT=8000
# File management
ATTACHMENTS_DIR=./attachments
# ATTACHMENT_MAX_DOWNLOAD_BYTES=209715200 # get_redmine_attachmentのdownloadは200MB制限
AUTO_CLEANUP_ENABLED=true
CLEANUP_INTERVAL_MINUTES=10
ATTACHMENT_EXPIRES_MINUTES=60
<略>
dockerイメージをビルドして起動します。
docker compose up --build
サーバーが起動すると、http://localhost:8000でアクセスできるようになります。MCPエンドポイントは/mcp、ヘルスチェックは/health です。
# open-webuiにログイン
docker compose exec open-webui bash
# ヘルスチェック確認
http://redmine-mcp-server:8000/health
---
{"status":"ok","service":"redmine_mcp_tools","auth_mode":"legacy","checks":{"redmine":"ok"}}
ひとまず、上記の通り出力されていれば、redmine-mcp-serverはredmineサーバにAPIで接続できています。
接続試験
open-webuiコンテナからredmine-mcp-serverにアクセスができるかを実際の流れに沿って確認してみます。
# open-webuiにログイン
docker compose exec open-webui bash
# initialiized通知
curl -i -X POST 'http://redmine-mcp-server:8000/mcp' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {
"name": "curl-test",
"version": "1.0"
}
}
}'
# tools/list
curl -i -X POST 'http://redmine-mcp-server:8000/mcp' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
--data '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'
# tools/call例
curl -i -X POST 'http://redmine-mcp-server:8000/mcp' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
--data '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "list_redmine_projects",
"arguments": {}
}
}'
MCPツール設計
利用可能なツール
この MCP サーバーは、Redmine と連携するための 45 個のツールを提供します (さらにREDMINE_MCP_EXPOSE_ADMIN_TOOLS=true、によって公開される 1 つのオペレーター ツールと、環境変数でオプトインする 5 つのプラグイン ゲート ツールがあり、すべて有効にすると最大 46 個になります)。詳細なドキュメントについては、ツール リファレンスを参照してください。
コアツール(40種類、常時利用可能)
これらのツールに必要なのは、Redmineのインスタンスと認証情報だけで、追加のプラグインや機能フラグは必要ありません。
- プロジェクト管理(9つのツール)
list_redmine_projects- アクセス可能なプロジェクトをすべて一覧表示しますlist_project_issue_custom_fields- プロジェクト用に設定された課題カスタムフィールドの一覧表示list_redmine_versionsプロジェクトのバージョン/マイルストーンを一覧表示するmanage_redmine_versionバージョン/マイルストーンの作成、更新、または削除list_project_membersプロジェクトのメンバーと役割を一覧表示します。summarize_project_status- プロジェクトの包括的なステータス概要を取得するlist_redmine_roles- Redmineインスタンスで定義されているすべてのロールを一覧表示します(有効なロールを見つけるためrole_ids)get_project_modulesプロジェクトで有効になっているモジュールを取得します。manage_project_memberプロジェクトメンバーシップの追加、更新、または削除
- 問題発生時の操作(13種類のツール)
get_redmine_issue- 詳細な問題情報を取得します(ジャーナルのページネーション、ウォッチャー、関連情報、子情報に対応)。list_redmine_issues- 柔軟なフィルタリング機能(プロジェクト、ステータス、担当者など)を使用して課題を一覧表示します。search_redmine_issues- テキストクエリで問題を検索create_redmine_issue- 新しい課題を作成するupdate_redmine_issue- 既存の問題を更新するdelete_redmine_issue- 不可逆的な削除を行う前に、必要な確認フラグと連鎖的な影響のプレビューを表示して、課題を完全に削除します。copy_issue- オプションのフィールドオーバーライドを使用して既存の問題を複製するlist_subtasks- 特定の親タスクのサブタスク(子タスク)を一覧表示するget_private_notes- 問題に関する非公開メモを取得するmanage_issue_relation- 課題関連のリスト表示、作成、または削除manage_issue_watcher- 課題のウォッチャーを追加または削除するmanage_issue_noteジャーナルノートのテキストを編集したり、プライバシー設定を切り替えたりするmanage_issue_category- 問題カテゴリの一覧表示、作成、更新、または削除- 注:名前でカスタムフィールド
get_redmine_issueを含めcustom_fieldsたりupdate_redmine_issue更新したりできます (例{"size": "S"})。
- 時間管理(4つのツール)
list_time_entriesプロジェクト、課題、ユーザー、日付範囲でフィルタリングして時間エントリを一覧表示するmanage_time_entry- タイムエントリを作成または更新する(user_id他のユーザーに代わってログを記録する場合に使用)list_time_entry_activities- 時間入力に利用可能なアクティビティの種類を確認するimport_time_entries- エントリごとのエラー報告機能を備えた、シーケンシャルなAPI呼び出しによるタイムエントリの一括インポート
- 発見/列挙(6つのツール):LLMが作成/更新ツールを呼び出す前に有効なIDを見つけるのを支援します
list_redmine_trackers- すべてのトラッカー(バグ、機能、サポートなど)を一覧表示します。list_redmine_issue_statuses- すべての課題ステータスとそのis_closedフラグを一覧表示しますlist_redmine_issue_priorities- すべての優先度レベルを一覧表示しますlist_redmine_users- ユーザーのフィルタリング/一覧表示(管理者のみ利用可能。名前とグループのフィルタリングに対応)get_current_user- 認証済みユーザーのプロファイルを取得します(管理者以外のユーザーにも有効です)list_redmine_queries- 保存済みのカスタムクエリの一覧表示(読み取り専用)
- 検索とWiki(2つのツール)
search_entire_redmine- 課題とWikiページ全体を対象としたグローバル検索(Redmine 3.3.0以降)manage_redmine_wiki_page- Wikiページの一覧表示、取得、作成、更新、削除、または名前変更
- ファイル操作(4つのツール)
list_filesプロジェクトのファイルセクションにアップロードされたファイルを一覧表示するupload_file- プロジェクトに新しいファイル(base64 コンテンツ)をアップロードします。必要に応じてバージョンに紐付けます。delete_fileプロジェクトからファイルを削除するget_redmine_attachment- 添付ファイルをダウンロードする(HTTPモードとstdioモードの両方で動作します)
- ガントチャート(ツール1つ)
get_gantt_chart- プロジェクトのタイムラインデータを取得する:日付、依存関係、マイルストーンに関する問題
- メタ(1ツール)
get_mcp_server_info- サーバーのバージョン、認証モード、読み取り専用状態、認証されたユーザー (current_user)、およびどのプラグインゲートツールファミリーが有効になっているかを報告します。最近リリースされた修正に依存する前にデプロイメントの遅延を検出したり、assigned_to_id="me"が に解決されることを確認したりするために使用します。
この他、Redmineにプラグインを入れることで利用できる機能があります。詳細はGitHubのREADMEをご確認下さい。
Open-WebUIへMCP登録
Open-WebUIからredmine-mcp-serverにMCP Streamable HTTPでアクセスできるように設定する。
管理者パネル

設定→連携

登録
・MCP Streamable HTTPの箇所ですが最初はOpenAIになっていますがクリックすると変わります
・IDはよくわかっていません…
・URLですが、ホストのIPにしていますがコンテナ名のredmine-mcp-serverが良いと思います
・緑のスイッチは有効無効でその左のリロードっぽいアイコンは接続確認です

モデルの設定
モデルに上記で作成したツールの登録や、ツールを優先して利用するようにシステムプロンプトを設定します。
以降の画像にあるモデル名がPhi3になっていますが、実はMCPをうまく理解できませんでした。私が試した範囲では、llama3.1:8b のみが期待する動作をしました。プロンプトとの相性かもしれません。うまく行ったよというモデルがあれば教えて下さい。失敗したモデルは、Qwen2.5:7b, Qwen3.5:4b, Phi3:8b, neoai, mistral:7b は何度か試した感じMCPを理解し操作しようとしませんでした。
モデルにツールを追加
設定からモデルの編集を選択

システムプロンプトの記載とツールにチェックを入れる

システムプロンプトの例
ツールを使うように指定しておかないと学習済データから一般的な回答をしたり期待しない結果となる可能性がある。不足は一般的な知識で補いつつ登録データを優先して出力するよう予め指示しておく必要がある。
あなたはRedmineのナレッジ検索アシスタントです。
質問に回答する前に、
必要に応じてRedmineを検索してください。
検索結果から
・発生原因
・対応内容
・関連チケット
を整理して回答してください。
推測ではなくRedmineの内容を優先してください。
この方式の最大の利点
RAGの場合
検索
↓
類似文書
↓
回答
MCPの場合
検索
↓
詳細取得
↓
追加検索
↓
分析
↓
回答
になります。
つまり
「AIがRedmineを操作して調査する」
という人間に近い動きになります。
Redmineのように「チケット」「コメント」「添付ファイル」「履歴」が蓄積される運用システムでは、RAGよりもMCPの方が自然に機能するケースが多いようです。
DifyによるMCP利用
Difyでも同様にMCPサーバを活用することが可能です。まずは完成イメージです。

流れ
- 開始により利用者の要求を sys.query として入力されます
- FETCH MCP TOOLS で redmine-mcp-server から操作手段と説明を取得
- LLMでユーザの要望を満たす手段を工夫して組み立てる
- TOJSON(コードブロック)で出力結果を加工する
- CALL MCP TOOLでLLMが作った手順を redmine-mcp-server経由でredmineへリクエストする
- LLM2で応答結果を整形する
- 回答で各結果を出力する
ツールの設定
まずツールからMCPを検索して「MCP SSE / StreamableHTTP」を選択しインストールします。


インストールしたMCPツールに上記でインストールしたredmine-mcp-serverを登録します。



この記載を整形して表示すると。。。
{
"server_name": {
"url": "http://127.0.0.1:8000/sse",
"headers": {},
"timeout": 50,
"sse_read_timeout": 50
}
}
を、以下のように修正します。
{
"redmine-mcp-server": {
"url": "http://192.168.1.18:8000/mcp",
"headers": {},
"timeout": 50,
"transport": "streamable_http"
}
}
ここで、同じdocker network内であればURLは http://redmine-mcp-server:8000/mcp でよいのですが、私の環境は別コンテナなのでホスト経由でアクセスするため上記のようなURLになっています。私のように別立てしている場合は皆様の環境似合わせて修正して下さい。
アプリの作成
スタジオから新しいアプリの作成をします。

チャットとして作成

作成するブロック全体構成

「開始」ブロックを設定します。

「FETCH MCP TOOLS」ブロックの作成
今回はredmine-mcp-serverしか登録していないので記述しなくても動いちゃいますが、複数のサーバを登録した場合は、MCP Servers Config Stringに「redmine-mcp-server」と記載するのだと思いますが、今回は未記入で進めます。(動作検証も未記入で実施しました)
その他特に変更なしです。

「LLM」ツールの使い方を学ぶ
ここのLLMでは取得したツールと使い方の一覧を工夫してユーザの目的を達成するために何をどうしたらよいかを考えツールとオプションをLLMに考えてもらいます。

システムプロンプト
あなたは与えられたMCPツールの仕様書(Tools List)を読み、ユーザの要望を満たすために実行すべき「ツール名」と「引数(JSON)」を決定するエージェントです。
【提供されたMCPツール仕様書】
{{FETCH MCP TOOLSの出力}}
【ユーザーの要望】
{{#sys.query#}}
必ず以下のフォーマットに従って、厳密なJSONのみを出力して下さい。以下の以外に余計な挨拶や解説やデバック用記述などや改行コードは一切不要です。
```json
{"tool_name": "選択したツール名", "arguments": {"引数のキー" : "値"}}
```
「ToJson」(コードブロック)
このコードブロックではLLMの出力を次のCALL MCP TOOLへ値を渡せるようにするためのデータの加工です。

import json
import re
def main(input_str: str) -> dict:
print("--- 最初の入力値 ---")
print(input_str)
# 正規表現で JSON 部分 ({ から }) をグループとして抽出
# assistant の前後にクォーテーションがあってもなくてもマッチするように修正
match = re.search(r'\{.*?(\{.*?\}).*?\}', input_str, re.DOTALL)
# .group(1) を使うことで、括弧 ( ) の中身の文字列だけを取得
json_text = match.group(0)
print("--- 抽出したJSON文字列 ---")
print(json_text)
try:
# 文字列を辞書オブジェクトに変換
data = json.loads(json_text)
print("--- パース成功 ---")
print(data)
# Difyの出力変数設定に合わせるため、辞書で包んで返却
return {
"tool_name": str(data.get("tool_name", "")),
"arguments": json.dumps(data.get("arguments", {}), ensure_ascii=False)
}
except json.JSONDecodeError as e:
print(f"!!! パースエラー発生: {e} !!!")
return {
"tool_name": None,
"arguments": f"JSONの解析に失敗しました: {str(e)}"
}
「Call MCP Tool」 工夫したツールでRedmineにアクセスする
利用者の目的を達成すべくLLMが選んだツールを用いてRedmineにredmine-mcp-server経由で問い合わせを行います。Tool Name は、ToJsonで加工して得た変数を設定。Argumentsも、ToJsonで加工した変数を設定。MCP Servers configはFetchの時も同様ですが今回は空白のままにしています。

「LLM2 」出力結果のまとめや整形など
CALL MCP TOOLの出力結果をまとめてもらったり、出力を整えてもらったりをここで行います。

システムプロンプト
【結果】
{{#CALL MCP TOOLの出力結果#}}
【まとめ】
得た結果である {{#CALL MCP TOOLの出力結果#}} を元にMarkDown形式に変換し利用者が読みやすい形で出力して下さい。
出力結果の整形なので、皆様のお好きなように記載いただければOKです!
「回答」
最後に何を出力するかですが、デバッグもかねてLLMとLLM2の値を出力してみてますが、こちらも皆様のお好きなように出力いただければと思います。

以上、MCP TOOLを使ってDifyでredmineの操作をするサンプルを作ってみました。実はDifyのバージョンが1.5.0と古い環境で試験してしまっているのですが、新しい環境ではツールの下にMCPタグができて、そこにMCP-Serverを登録し、スタジオでは、エージェントブロックを追加するだけで、このFETCHとCALLを一緒くたにLLMを介して動作するような仕組みになっているようです。
まぁ考え方は一緒なので次回はバージョンをあげて、エージェントブロックを使ってのMCPの構成を構築してみようと思います。
Difyによるエージェント動作
Difyのバージョンを上げてツールタブにMCPサーバを登録できるようになりましたので早速試してみましたので以下にメモをします。
Difyのバージョンアップ
事前に現在稼働のdifyを終了しておき、gitのfetchで最新情報を取得して最新のブランチに切り替えます。切り替えたら docker/.env ファイルがそのまま残っている事を確認した上で起動します。
cd ~/work/dify <--- git cloneしたホルダに移動
cd ./docker/
docker compose stop
docker compose down
git remote -v
origin https://github.com/langgenius/dify.git (fetch)
origin https://github.com/langgenius/dify.git (push)
git fetch
git branch -a|grep 1.14.2-fix.11
remotes/origin/hotfix/1.14.2-fix.11
git switch remotes/origin/hotfix/1.14.2-fix.11
docker compose up -d
ツールのMCPにてサーバを登録
ツールからMCPを選択

MCPサーバを追加

MCPサーバの情報を登録



スタジオでアプリの作成
アプリは以下のように作ります。「開始」でqueryをstringsで定義して、「エージェント」と言う名のMCPを用いたLLMなブロックを追加し、「回答」はそのエージェントの出力をそのまま表示するようにしています。
以下、エージェントの設定の例です。

エージェンティック戦略には、FunctionCallingと、ReActがあるのですが llama3.1:8bでReActを選ぶとMCPサーバとうまくやり取りをしてくれなくなり、こうしたらできる、あぁしたらできると説明するのみになってしまいました…
FunctionCalling
Recommended. Uses the model's native function calling capability for tool invocation. Works best with most modern models (GPT-4o, Claude, Qwen, etc.).
ReAct
Text-based reasoning strategy (Thought → Action → Observation loop). Best for models that do NOT support function calling. If your model supports function calling, use the FunctionCalling strategy instead for better results.
モデルはローカルLLMのOllamaでモデルはllama3.1:8bとしています。ここはより賢いLLMが良いのでGeminiのAPIとかChatGPTなAPIが設定できるならそのほうが良いと思います。
INSTRUCTIONには以下を設定しました。
あなたはredmineのエージェントです。
ユーザのリクエストである{{#sys.query#}}を満たすために以下を実行して下さい。
redmine-mcp-serverよりMCPサーバのツールと仕様書(Tools/List)を読み込んで使い方を学習し、学習したツールを工夫しMCPを使ってredmine-mcp-serverにtool/callでコマンドを送ってredmineを操作してユーザの要望に答えてください。
Queryはそのまま以下の通りにしましたが、上記の2行目をいかに記載すべきなのかもしれません。
{{#sys.query#}}
Maximum Iterationsはデフォルト3ですが10にしてみています。根拠はありません。最大500まで設定できるようですが、どういったシーンでどれくらいの設定が必要なのか機会があれば調べて最適な数字を設定できるよう勉強しておきます…
以上で、MCPのFetchとCallを別々に行っていたもんがエージェント動作として利用者の目的を達成するまで、Callを繰り返し実行させたりができるようになりました!
あと、追加などの動作はlllama3.1:8bでは失敗することがありますが、Gemini2.5 Flashを選択すると同じユーザリクエストでもサクッと登録されちゃったりしますので、やはりモデルはよりパラメータ数の多いものや最新のものを利用するのが良さそうです。
エージェント動作はまだまだ可能性がありそうなのでもっと遊んでみようと思います〜
