2
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?

【MCP】自社プロダクトのAPIを使用してMCPを作ってみた ~ローカルMCP編~

Last updated at Posted at 2025-12-04

どうもこんにちは。
今回は、弊社サービスのAPIを使用してMCPを作成してみました。

今回、MCPを作成した理由は以下です。

自社プロダクトMCPを作成した理由

  • MCPに対する理解を深めたかったから
  • 業務に役に立つものを作りたかったから
  • Amazon Bedrock AgentCoreを使用してMCPの構築を行いたかったから

今回は ローカルMCP編 なので、「 MCPに対する理解を深めた 」点と、「 業務に役に立つものを作りたかった 」という2点について深ぼっていきたいと思います。

MCPについて

まず、MCPについてですが、これはみなさんご存知かと思います。私は、「 AIエージェントが使える ツール を集めたもの 」と認識しています。
ただ、ツールとはちょっと役割が違うのかなと思っています。

私の思うツールとMCPの違い

ツール MCP
立場 AIエージェントがデフォルトで持っている武器 AIエージェントが アクセス することで使えるようになる武器
処理の規模 小さめ 大きめ
拡張性
実装のレベル

処理の規模 については、デフォルトの武器をどれだけ大きくするか によって左右されるものかと思います。
拡張性については、ツールは AIエージェントと同じランタイムに実装される のが一般的かと思います。この場合、ツールを増やしたり改修したりする時には、AIエージェントのランタイムを直接編集する必要があります。一方でMCPは、AIエージェントとは別のランタイムに実装される のが一般的です。そのため、AIエージェントのランタイムとは分離してツールを増やしたり改修することができます。

なぜ自社プロダクトのMCP?

弊社では、自社プロダクトを運用している中で、エンジニア以外の社員がハードウェアのログを取得して調査 したり、 コンテンツを放映するスケジュールを組む などの業務が発生しています。

近年のAI社会では、「サーバから取得したログファイルをAIに読ませる」「インターネット上から必要な情報を取得してレポートをまとめる」というようなことが容易にできるようになっています。
これを応用して「調査すべきログファイルを自立的に取得させて読ませる」「スケジューリングをAIに任せる」ということを実現できないかと考え、MCPを作成してみようと考えました。

MCPを作るにあたってのハードルは?

どうやってプロダクトのDBにアクセスする?

MCPを作る時に、「どうやってデータを取ってくるか」「どうやってデータを登録するか」を考える必要があります。例として、以下が挙げられます。

  • プロダクトのAPIを経由する
  • ライブラリなどを使用してプロダクトのDBにアクセスする

2つ目の方ができることは増えますが、セキュリティ面を考慮するする必要があったり、1から構築を行う必要があるので難易度が高いです。

今回はやりたいことがAPIで実現できそうだったので、難しいことは考えずにAPI経由でMCPサーバからDBにアクセスするようにしました。

どうやって提供する?

提供方法はまだ検討段階ですが、以下の方法が考えられます。

  • MCPサーバのソースコードを配布する
  • MCPサーバをAWSやGCPなどに公開して、リモートMCPサーバとして公開する
  • MCPサーバは非公開にし、MCPが接続されたAIエージェントをアプリケーションの機能として実装する

より柔軟なのは、2つ目かなと思っています。リモートMCPサーバとして公開しておけば、ClaudeやChatGPTなどのあらゆるサービスから簡単に接続することができるようになります。非エンジニアのユーザに使ってもらうためには多少の説明は必要になりそうです。

1つ目は、ローカルMCPサーバとして動作させることを前提としています。コストは抑えることができますが、エンジニア以外のユーザが使用するのは難しくなります

3つ目の場合は、エンジニアでも非エンジニアのユーザもMCPサーバを意識することなくMCPを使用することができます。ただし、AIチャット機能をアプリケーションに実装する必要があるので、公開するまでに時間がかかります。

今回の私の要件は、「エンジニア, 非エンジニアの業務を効率化すること」なので、2つ目か3つ目が有効であると考えます。

MCPサーバの作り方

参考までに、以下に開発方法を示しておきます。今回は検証でもあったため、ローカルで動作させることを想定しています。

開発環境は?

開発環境は以下です。

  • Python3.13
    • uv仮想環境
    • FastMCPライブラリ
  • Docker

Pythonを選んだ理由は、MCPの中でAIエージェント使用するケースを考えた時に、StrandsAgentsが実装しやすいな と考えたからです。
また、Dockerを使用している理由は、Amazon Bedrock AgentCoreへデプロイするために、ECRへデプロイする必要があったからです。

開発方法

1. 環境を用意

ターミナルで以下を実行します。

$ mkdir playground && cd playground
$ mkdir sample_mcp && cd sample_mcp
$ uv init --python 3.13
$ uv add fastapi 'uvicorn[standard]' mcp httpx strands-agent    # あと何か追加したけど忘れた...

プロジェクトにmain.pyというようなものが作成されていたら、mcp_server.pyと名前を変えておきましょう。(なんとなく)

2. MCPサーバを構築していく

まず、書き出しは以下としています。

from mcp.server.fastmcp import FastMCP
from starlette.responses import JSONResponse
import httpx
import json
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
from strands import Agent

mcp = FastMCP(host="0.0.0.0", stateless_http=True)

ツール関数を作成していく

次に、AIエージェントが実行できるツールを用意していきます。
今回はサンプルとして、ユーザ一覧情報を取得するAPIを叩くツールを用意します。

# エラーが発生した場合に呼び出す関数
def error_handler(message: str) -> str:
    return json.dumps({ 'success': False, 'error': message })

# GETリクエストを送信する関数
def request_get(url: str, headers: dict, params: dict) -> JSONResponse:
    try:
        with httpx.Client() as client:
            response = client.get(url, headers=headers, params=params)
            response.raise_for_status()
            return api_success_handler(response.json(), response.status_code)
    except Exception as e:
        return api_error_handler(str(e))

# ユーザ一覧を取得するツール関数
@mcp.tool()
def get_users(x_api_key: str, api_id: str) -> str:
    """APIからユーザの一覧情報を取得します
    必須パラメータ:
    - x_api_key: APIキー
    - api_id: API ID
    """
    try:
        headers = { "X-Api-Key": x_api_key, "Accept": "application/json", "Content-Type": "application/json" }
        params = { "api_id": api_id }

        response = request_get(get_users_url, headers, params)
        return json.dumps(response.body.decode())
    except Exception as e:
        return error_handler(str(e))

ここで重要な点は3つです。

1. デコレータ

ツールとして使用する関数には、@mcp.tool()というデコレータを関数の前に記述します。これによって、以下のことができるようになります。

  • get_users関数をツールとして使用できるようになる
  • 関数の docstring がツールの説明として使われる
  • 関数のパラメータと型アノテーションに基づいて入力スキーマを生成する
  • パラメータの検証とエラー報告を処理する

ツールとして呼び出さない関数には、デコレータをつける必要はありません。

2. 関数のパラメータと型を定義する

関数のパラメータに型を指定しておくことで、正確なJSONパラメータを関数に送信することができるようになります。

# 入力パラメータがすべて文字列の場合
def get_users(x_api_key: str, api_id: str) -> str:

# 入力パラメータにint型が含まれる場合
def get_user(x_api_key: str, api_id: str, user_id: int) -> str:

# 入力パラメータにboolean型が含まれる場合
def get_users(x_api_key: str, api_id: str, is_admin: bool) -> str:
3. 出力するデータの型を定義する

関数の戻り値の型を指定しておくことで、適切な形式にデータを変換してデータを返してくれます。

  • str : TextContentとして送信
  • dict、list、Pydantic、BaseModel : JSON文字列にシリアル化され、TextContentとして送信
  • bytes : Base64 エンコードされ、BlobResourceContents として送信 (多くの場合、EmbeddedResource内)
  • fastmcp.Image : 画像データを簡単に返すためのヘルパークラス。ImageContentとして送信
  • None : 空のレスポンス (クライアントにコンテンツは返されない)

3. MCPサーバを起動する

ターミナルで、以下を実行するとPythonサーバが起動します。

$ uv run python mcp_server.py

4. クライアント側で設定を行う

MCPを使用するクライアント側ツールによりますが、以下のようなJSONを定義します。

{
  "mcpServers": {
    "sample_mcp_servers": {
      "url": "http://localhost:8000/mcp",
      "enabled": true
    }
  }
}

正常に接続ができれば、MCPサーバを使用することができるようになります。

参考サイト

2
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
2
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?