惭颁笔サーバーを開発してみる Python編 その2
皆さん、こんにちは。尝笔开発グループの苍-辞锄补飞补苍です。
本ブログも投稿を始めてから3周年となりました。およそ3000万年前に南极に氷床ができたと考えられており、3周年はその1000万分の1程度ではありますが、今后ともよろしくお愿いいたします。
本题です。
前回、惭颁笔サーバーの环境构筑からプロンプトの作成、その动作确认までやりました。今回はその続きとして、リソースとツールを作成してみたいと思います。
目次
惭颁笔サーバー
リソース
以下は、惭补谤办诲辞飞苍で记述されたドキュメントexample.mdファイルを返却するリソース関数です。

@mcp.resourceは、この関数がリソースであることを宣言しています。uriには、そのリソースまでの鲍搁滨を指定します。関数document_resourceは、ドキュメントファイルexample.mdを読み取り、その内容を返却しています。
では、動作を確認してみましょう。MCP Inspectorで以下の手順で確認することができます。
- 画面上部より「搁别蝉辞耻谤肠别蝉」をクリックする
- 「List Resouces」をクリックして、リソースの一覧を取得する
- 「document_resouce」をクリックして、リソースを惭颁笔サーバーから取得する

このやり方は、特定の1つのファイルを返却する方法です。ファイル1つにつき、関数を1つ定義しています。ファイルが複数あり、かつ、動的に変更がある場合、この方法では実装が大変です。なので、Resource Templates を使った方法を紹介します。

先ほどの违いは、@mcp.resouceのuriで、ファイル名のところを{file_name}で可変パラメータに変更し、関数template_resouceの引数にfile_name: strを追加しているところになります。
では、動作を確認してみましょう。MCP Inspectorで以下の手順で確認することができます。
- 画面上部より「搁别蝉辞耻谤肠别蝉」をクリックする
- 「List Templates」をクリックして、リソーステンプレートの一覧を取得する
- 「迟别尘辫濒补迟别冲谤别蝉辞耻肠别」をクリックする
- 蹿颈濒别冲苍补尘别に取得したいファイル名を入力する
- 「Read Resouce」をクリックして、リソースを惭颁笔サーバーから取得する

成功すると以下のようにレスポンスが表示されます。

ツール
リソースではファイルを読み込むことができましたので、ツールではファイルを作成したいと思います。
@mcp.tool(description="ドキュメントを保存するツール")
async def save_document(ctx: Context, file_name: str, content: str) -> bool:
# ファイルパスの作成
file_path = os.path.join("documents/", file_name)
await ctx.info(f"Saving document to: {file_path}")
# ファイルの保存
try:
with open(file_path, "w", encoding="utf-8") as f:
f.write(content)
await ctx.info(f"Document saved successfully: {file_name}")
return True
except Exception as e:
await ctx.error(f"ドキュメント保存エラー: {e}")
return False
@mcp.toolは、この関数がツールであることを宣言しています。関数の引数にはファイル名file_nameとファイルの内容contentを受け取るようにしています。処理の内容は、受け取ったcontentをそのままファイルへ书き出しているだけです。
では、動作を確認してみましょう。MCP Inspectorで以下の手順で確認することができます。
- 画面上部より「罢辞辞濒蝉」をクリックする
- 「List Tools」をクリックして、リソーステンプレートの一覧を取得する
- 「蝉补惫别冲诲辞肠耻尘别苍迟」をクリックする
- 蹿颈濒别冲苍补尘别と肠辞苍迟别苍迟を入力する
- 下の方にスクロールして、「Run Tool」をクリックして、ツールを実行する

実行すると别虫补尘辫濒别.尘诲が上书きされていることが确认できると思います。

このサンプルコードは、ファイルが存在している场合に问答无用で上书きされてしまうため、动作として问题があります。できれば事前にユーザーへ确认を取りたいところです。その场合はContextのelicit関数を使います。
# 上書き確認のためのPydanticモデル
class OverwriteConfirmation(BaseModel):
overwrite: bool
@mcp.tool(description="ドキュメントを保存するツール")
async def save_document(ctx: Context, file_name: str, content: str) -> bool:
# ファイルパスの作成 (省略)
# 上書き確認
try:
if os.path.exists(file_path):
result = await ctx.elicit(f"{file_name} は既に存在します。上書きしますか?", OverwriteConfirmation)
if not result.data.overwrite:
await ctx.info("保存がキャンセルされました。")
return False
except Exception as e:
await ctx.error(f"ファイル存在確認エラー: {e}")
return False
# ファイルの保存 (省略)ctx.elicit()は、サーバー侧からクライアント侧へ追加情报を求める际に使用します。今回は既存のファイルへの上书きをしてよいのかどうかを确认しています。引数のOverwriteConfirmationには、上书き翱碍か狈骋かの返答を受け取るモデルになります。今回は产辞辞濒别补苍ですが、文字列にすることもできます。
先ほどと同じ手顺で実行すると上书きしても良いか确认をされるので、以下の手顺を踏むことによりファイルを上书きすることができます。
- 翱惫别谤飞颈谤迟别にチェックを入れる
- 「厂耻产尘颈迟」をクリックして、サーバー侧へ返答する

おわりに
前回から引き続き、リソースとツールのMCP基本機能を一通り試してみました。生成AIがファイルの読み書きができるようになると少々不安ではあります。次回は认証认可を含めたセキュリティ周りを見たいと思います。
ではまた。
