はじめに
こんにちは。法人事業部プロダクト開発グループの入江です。 エンジニアの皆さんは日々の開発業務でTracのようなチケット管理システムを使っていますでしょうか?
あすけんの開発では、仕様に関する議論の多くが社内Tracシステムを用いて管理されています。
このような管理方法になったのは、過去のいきさつや開発体制の都合によるもので、過去十数年分の仕様に関する情報が蓄積されています。 現在の開発においても、現行仕様調査のために古いチケットを検索し、数十件、多い時には百件近くにわたるコメントを読み込み理解するような作業をしていました。 この作業を効率化するために、TracのチケットにアクセスするMCPサーバーを作成してみました。
今回は、そのMCP開発の経験から得られた知見や工夫点を共有したいと思います。 MCPを作ってみたいけどアイデアが浮かばない方や、実際に作る際の参考になれば幸いです。
対象読者
- AIを活用した業務効率化に興味があるエンジニア
- 社内の既存システムとAIを連携させたいと考えている方
- MCPサーバを作ってみたいがアイデアが浮かばない方
- 実際にMCPサーバを開発する際の参考事例を探している方
MCPについて
Model Context Protocol(MCP)は、AIエージェントにさまざまなデータソースやツールに接続するための標準化された方法を提供するプロトコルです。 Anthropicより発表されたこのプロトコルは今では、Claude Desktopを始めとしてRooCode、VSCode GitHub Copilot、Devinなど各種のAIエージェントに実装されており、 MCPを通じて外部環境にアクセスし、AIエージェントの能力を一層高めるものとして利用されています。
外部環境にアクセスすることで、LLMが通常は回答できない、業務上に特化した知識や最新の情報に基づいた回答ができるようになります。
以前は、AIエージェントに外部の知識をインプットする際は、独自に連携部分を作り込む必要がありましたが、このプロトコルにより連携がしやすくなりました。
今回作成したMCPは、社内のTracチケット管理システムにアクセスし、以下の機能を提供するものです:
- キーワードやステータスによるチケット検索
- チケット詳細情報の取得
- チケットコメントの取得
これにより、AIエージェントがTracのチケット情報を直接参照し、過去の仕様変更の経緯や議論の内容を理解した上で回答できるようにしました。
今回のMCPを作った動機
このMCPを作った主な動機は、開発業務における既存仕様調査の効率化です。 あすけんは、約十数年にわたる開発の歴史があり、過去の仕様変更や議論がTracチケットに蓄積されています。 新しく開発する際には、関連する機能の過去のチケットを調べて、どのような経緯で現在の仕様になったのかを理解する必要があります。 この作業には以下のような課題がありました:
- 関連するチケットを探すのに時間がかかる
- 長いチケットの内容を全て読み解くのが大変
- 複数のチケットにまたがる議論を追うのが難しい
これらの課題を解決するために、AIエージェントにTracチケットの情報を直接参照できるようにし、 Tracのチケットの要約や関連付けを行ってもらうことで既存仕様調査が楽になるのではないかと考え、MCPサーバを作ることにしました。
方式
Tracチケットの情報を返却するMCPサーバーをどのように作成するかを考えた結果、以下のような方式で実装することにしました。
- AIエージェントとのインターフェースにはFastMCPフレームワークを使用
- MCPサーバからTracの情報取得にはXML-RPC Pluginを利用
PythonにはXML-RPCを扱うための標準ライブラリがあるため、MCPサーバとXML-RPCの処理を簡単に組み合わせることができます。
TracにはXML-RPC APIを提供するプラグイン「TracXMLRPC」があります。このAPIを利用することで、API経由でチケットの検索や詳細情報の取得が可能です。もともとTracにはプラグインが入っていなかったのですが、今回のMCPサーバからの利用を目的として新たにプラグインを追加しました。
MCPサーバの実装には、Python用のMCPフレームワークである「FastMCP」を使用しました。FastMCPは、MCPサーバーの実装を簡単に行えるフレームワークです。メソッドに対してアノテーションを付与することで簡単にMCPサーバとしてAPIを公開することができるほか、docコメントから説明を自動で生成してくれる機能が便利です。
例えば次のような形で定義できます(このコードは私がMCPサーバのサンプルとして最初に作成したニュートン法によるn乗根を求めるプログラムです)。
from mcp.server.fastmcp import FastMCP mcp = FastMCP("n-square root") @mcp.tool() def nroot(n: int , value: int, sigma: float) -> str: """Find the n-square root of the given number with Newton's method. The function's arguments are n to the power of n, value to calculate the n-square root, and sigma as the convergence condition. """ # 関数定義 # ...省略... if __name__ == "__main__": mcp.run()
このように公開したいメソッドに対していくつかの記述を追加するだけで、MCPサーバを作成することができます。
このプログラムをMCPサーバとして登録すると下記の図のように、メソッド名、引数、docコメントが自動で公開されます。
以上のことをまとめると全体の概略は下記のようになります。
少し工夫した点
FastMCPでは通常、アノテーションでツールの説明を定義しますが 。この方法では、MCPクライアントに公開されるAPIの説明を動的に変更できません 。
そこで、汎用的なTracチケット検索ツールを作成しつつ、MCPクライアントにTracで管理されている情報を公開するため 、
アノテーションではなく、ツールの説明文を直接文字列で定義する方法を採用しました 。具体的には、環境変数から取得したTracサーバーの説明文をドキュメントに埋め込みました 。
例えば、通常は以下のアノテーションで定義しますが 。
@MCPTool( name="search_tickets", ) async def search_tickets( self, keyword: str, status: str | Any ) -> list[dict[str, Any]]: """ # Tracチケット検索ツール ## 概要 キーワードでチケットを検索します。 ## アクセス先のTracに関する情報 """
代わりに、ツールの説明文を文字列として定義し、FastMCPのadd_toolメソッドでAPIを登録しました 。
search_tickets_detail = f""" # Tracチケット検索ツール ## 概要 キーワードでチケットを検索します。 ## アクセス先のTracに関する情報 {trac_description} """ self.mcp = FastMCP("Trac Mcp server") self.mcp.add_tool(self.search_tickets, name="search_tickets", description=self.search_tickets_detail)
trac_description
は環境変数から取得するため、同じコードで異なるTracサーバーに接続する場合でも、環境変数で説明文を動的に変更できます 。
開発において便利だと思ったもの
MCP開発中に特に便利だと感じたのは、MCP Inspectorです。
MCP InspectorとはMCPサーバをテストおよびデバッグするための開発ツールです。
AIエージェントを使わなくても、MCPサーバーの動作確認が手軽に行えます。 自分がこのツールを知ったのはおおかたMCPサーバを作ってしまった頃でしたが、これを使うことでMCPサーバーの開発が非常にスムーズになりました。
以下のようなコマンドでMCP Inspectorを起動し、ブラウザ上でMCPサーバの動作を確認できます:
npx @modelcontextprotocol/inspector --config ~/config.json --server trac-mcp
起動すると下記のような画面が表示され、MCPサーバへの接続や各種APIへのアクセスができるようになります。
これにより、AIエージェントとの連携前に、MCPサーバー単体での動作確認が容易になりました。
作ってみた結果
実際にこのMCPを使ってみたところ、期待通りの効果が得られました。AIエージェントがチケットの内容をうまくまとめてくれるようになり、 1つ1つのコメントを読解していく時間が大幅に短縮されました。 特に以下のような場面で効果を実感しました:
- 複数のチケットにまたがる議論の流れを把握する場合
- 長文のチケット内容から重要なポイントを抽出する場合
- 特定のキーワードに関連するチケットを横断的に調査する場合
100件以上のコメントがついたチケットを数十秒で要約することができた時は、とても便利だと感じました。
また、GitHub MCPと連携することで、AIエージェントが自律的にコメント中のGitHubのリンクを辿ってコードベースで仕様を追跡するようになり、 さらに調査が効率的になりました。
以下は、実際にチケット内容を取得して、要約している画面です。
詳細はお見せできませんが、チケットの概要、その時の課題や対応内容をまとめてくれます。
作ったあとでわかったこと
askenではRooCodeの他にもCursorやVSCode GitHub Copilotなど複数のAIエージェントクライアントをサポートしています。
私はRooCodeを使って最終的な動作確認を行いました。 社内展開してみると、Cursorだとうまく動作しないことがわかりました。
具体的には、Cursorでは一部のパラメータが正しく解釈されずオプション項目を必須にしてしまうという挙動がありました。 この問題についてはツールの説明文を調整することで解消できました。 当時、RooCodeもCursorもモデルはClaude Sonnet 3.7を利用していたため、モデルの差ではなく AIエージェントの内部プロンプトの差異により発生したのではないかと思われます。
この経験から、社内ツールとして作る際は、社内でサポートしている全ての製品で一通り動作確認をしておくことが重要だと感じました。
- 各AIエージェントクライアントでの挙動の違いを確認する
- ツールの説明文やパラメータ定義を明確にする
- エラーメッセージを分かりやすくする
これは後で知ったのですが、PydanticのAnnotated機能を利用すると、パラメータごとに説明文を定義することができるようです。
async def search_tickets( self, keyword: Annotated[str, Field(description="検索キーワード", title="検索キーワード")], status: Annotated[str | Any, Field(description="チケットステータス",title="チケットステータス") ]= None )
これを使うことで、MCPクライアント側でのパラメータの説明がより明確になり、AIエージェントが適切に解釈してくれると思います。
まとめ
TracチケットにアクセスするMCPを作成することで、調査業務の効率化が図れました。 MCPの開発自体も、FastMCPのようなフレームワークを使うことで比較的少ないコード量で実現できました。
MCPを作る際のポイントは以下の通りです:
- 日常業務の中で繰り返し行っている作業を見つける
- その作業をAIエージェントに任せることでどれだけ効率化できるかを考える
- 既存のAPIやプラグインを活用する
- 動的なドキュメント生成など、必要に応じて工夫を加える
- 複数のクライアントでの動作確認を忘れない
皆さんも、日々の業務の中で「これをAIエージェントに任せられたら便利だな」と思うことがあれば、MCPの開発を検討してみてはいかがでしょうか。 MCPにより、AIエージェントの能力を最大限に引き出し、業務の効率化を図ることができるかもしれません。
お知らせ
askenでは6/30にAIの勉強会を開催予定です。
askenの開発現場でAIを活用しているエンジニアが登壇しますので、ご興味のある方はご参加ください。
採用について
askenではエンジニアを絶賛募集中です。
まずはカジュアルにお話しできればと思いますので、ぜひお気軽にご連絡ください!
https://hrmos.co/pages/asken/jobs