OpenAI Responses APIでMCP連携|Python実装・承認フロー

Responses APIとMCPをPythonで接続する実装・承認フロー LLM

OpenAIのResponses APIでは、リモートMCPサーバーをtoolsへ登録するだけで、モデルから外部ツールを呼び出せます。

前回の「MCPとFunction Callingの違い」では設計上の使い分けを整理しました。今回は実装編として、PythonからMCPサーバーへ接続する最小コード、利用ツールの制限、承認フローまでを順番に解説します。

この記事を読むと、次のことが分かります。

  • Responses APIへリモートMCPサーバーを登録する方法
  • allowed_toolsで使えるツールを限定する方法
  • require_approvalで人間の承認を挟む方法
  • OAuthが必要なコネクターとの違い
  • 本番運用で避けたい設定

Responses APIとMCPサーバーの接続構成

スポンサーリンク

Responses APIのMCP連携とは

Responses APIには、組み込みツールの一種としてmcpがあります。自分で関数の実行処理を書くFunction Callingとは異なり、OpenAI APIがリモートMCPサーバーからツール一覧を取得し、必要に応じて呼び出します。

基本構成は次の4要素です。

要素 役割
type mcpを指定する
server_label 応答内でサーバーを識別する名前
server_url リモートMCPサーバーのURL
require_approval ツール実行前の承認ルール

リモートMCPサーバーは外部システムです。プロンプトや機密データが送られる可能性があるため、信頼できる運営元・コード・権限範囲を確認してから接続してください。

スポンサーリンク

Pythonの実行環境を準備する

OpenAI SDKをインストールする

Python 3.10以降を想定します。仮想環境を有効にしたうえで、OpenAI SDKを更新します。

pip install -U openai

APIキーを環境変数へ設定する

APIキーはコードへ直接書かず、環境変数OPENAI_API_KEYへ保存します。

export OPENAI_API_KEY="your-api-key"

OpenAI()は、この環境変数を自動的に読み込みます。GitHubへ公開するファイルやNotebookへAPIキーを貼り付けないようにしましょう。

MCPサーバーへ接続する最小コード

まずは、OpenAI公式ドキュメントでも例示されているデモ用MCPサーバーへ接続します。以下はダイスを振るツールだけを許可した最小例です。

from openai import OpenAI

client = OpenAI()

response = client.responses.create(
    model="gpt-5.6",
    tools=[
        {
            "type": "mcp",
            "server_label": "dmcp",
            "server_description": "ダイス計算を行うデモ用MCPサーバー",
            "server_url": "https://dmcp-server.deno.dev/mcp",
            "allowed_tools": ["roll"],
            "require_approval": "never",
        }
    ],
    input="2d4+1を計算してください",
)

print(response.output_text)

この例では説明を単純にするため、承認を省略しています。require_approval: "never"は、信頼済みの読み取り専用ツールなど、影響範囲を理解できている場合に限定してください。

実行時に起きること

  1. APIがMCPサーバーからツール一覧を取得する
  2. モデルが入力内容からrollの利用を判断する
  3. MCPサーバーがツールを実行する
  4. 実行結果を踏まえてモデルが最終回答を生成する

Function Callingのように、ツール呼び出しを受け取って自分のPythonコードで関数を実行し、その結果をAPIへ返す処理は不要です。

Responses API自体の基本は「OpenAI Responses API入門」、アプリ内関数を呼びたい場合は「Function Calling入門」も参考にしてください。

allowed_toolsで利用範囲を限定する

すべてのツールを公開しない

MCPサーバーによっては、数十個のツールを提供しています。すべてをモデルへ見せると、選択精度だけでなく、コストや待ち時間にも影響します。

利用するツールが決まっている場合は、allowed_toolsで許可リストを指定します。

mcp_tool = {
    "type": "mcp",
    "server_label": "knowledge_server",
    "server_url": "https://example.com/mcp",
    "allowed_tools": ["search_documents", "read_document"],
    "require_approval": "always",
}

この設定では、サーバー側に削除・更新ツールが存在しても、モデルへ読み込まれるのはsearch_documentsread_documentだけです。

最小権限で考える

本番環境では「使うかもしれない」ツールを並べるのではなく、ユースケースごとに必要なツールだけを渡すのが基本です。

  • 調査エージェント:検索・読み取りだけ
  • 社内アシスタント:閲覧と下書き作成まで
  • 更新エージェント:対象リソースを限定し、承認を必須化
  • 削除・購入・送信:原則として自動承認しない

MCPツールの実行前に承認を入れる

外部送信やデータ更新など、結果を元に戻しにくい処理には人間の承認を挟みます。

MCPツール承認フロー

1回目のリクエストで承認要求を受け取る

require_approvalalwaysにすると、モデルがツールを選んだ時点でmcp_approval_requestが返ります。

from openai import OpenAI

client = OpenAI()

mcp_tool = {
    "type": "mcp",
    "server_label": "dmcp",
    "server_description": "ダイス計算を行うデモ用MCPサーバー",
    "server_url": "https://dmcp-server.deno.dev/mcp",
    "allowed_tools": ["roll"],
    "require_approval": "always",
}

first = client.responses.create(
    model="gpt-5.6",
    tools=[mcp_tool],
    input="2d4+1を計算してください",
)

approval_request = next(
    item for item in first.output
    if item.type == "mcp_approval_request"
)

print(approval_request.name)
print(approval_request.arguments)

アプリ側では、ツール名・引数・接続先を表示し、ユーザーに実行可否を確認します。引数をそのまま信用せず、自分のアプリ側でも許可範囲を検証してください。

承認結果をResponses APIへ返す

承認された場合は、previous_response_idmcp_approval_responseを使って処理を継続します。

second = client.responses.create(
    model="gpt-5.6",
    tools=[mcp_tool],
    previous_response_id=first.id,
    input=[
        {
            "type": "mcp_approval_response",
            "approval_request_id": approval_request.id,
            "approve": True,
        }
    ],
)

print(second.output_text)

拒否する場合はapproveFalseにします。承認画面を閉じた場合や一定時間操作がない場合も、拒否として扱う設計が安全です。

コネクターを使う場合

OpenAIが管理するコネクターも、Responses API上ではtype: "mcp"として扱います。リモートMCPサーバーとの主な違いは、server_urlではなくconnector_idとOAuthアクセストークンを使う点です。

import os

from openai import OpenAI

client = OpenAI()

response = client.responses.create(
    model="gpt-5.6",
    tools=[
        {
            "type": "mcp",
            "server_label": "google_calendar",
            "connector_id": "connector_googlecalendar",
            "authorization": os.environ["GOOGLE_CALENDAR_OAUTH_ACCESS_TOKEN"],
            "require_approval": "always",
        }
    ],
    input="今日の予定を確認してください",
)

アクセストークンもAPIキーと同様に機密情報です。ログやエラーメッセージ、ブラウザへ返すレスポンスへ含めないでください。

よくあるエラーと確認ポイント

MCPサーバーへ接続できない

  • server_urlが外部から到達できるか
  • HTTPS証明書が有効か
  • サーバーがResponses APIから利用できるリモートMCP形式か
  • 認証ヘッダーやOAuthトークンが必要ではないか

ローカルPCのlocalhostは、そのままではOpenAI APIから接続できません。非公開・社内ネットワーク上のサーバーには、対応する安全な接続方法が必要です。

ツールが選ばれない

server_descriptionと各ツールの説明が曖昧だと、モデルが利用場面を判断しづらくなります。ツール名だけでなく「何ができるか」「いつ使うか」「何を返すか」を具体的に記述します。

応答が遅い・コストが増えた

公開するツール数が多すぎないか確認してください。allowed_toolsで対象を絞り、会話内では取得済みのmcp_list_tools情報を文脈に維持すると、毎回のツール一覧取得を避けやすくなります。

本番運用前のチェックリスト

  • ✅ 接続先MCPサーバーの運営元とコードを確認した
  • allowed_toolsで必要なツールだけを許可した
  • ✅ 更新・送信・購入・削除には承認を設定した
  • ✅ ツール引数をアプリ側でも検証した
  • ✅ APIキーとOAuthトークンを環境変数で管理した
  • ✅ タイムアウト・再試行・失敗時の動作を決めた
  • ✅ ツール名、承認結果、処理時間を監査ログへ残した
  • ✅ エラー表示から機密情報を除外した

まとめ

Responses APIからMCPサーバーを使う最小構成は、toolstype: "mcp"server_labelserver_urlを登録するだけです。

ただし、本番利用で重要なのは接続できることより、接続範囲を制御できることです。

  1. allowed_toolsで公開するツールを絞る
  2. 影響のある処理はrequire_approvalで止める
  3. ツール引数と権限をアプリ側でも検証する
  4. 信頼できるMCPサーバーだけを利用する

まずは読み取り専用ツール1個から試し、監査ログと承認画面を確認してから対象を増やすと安全です。

参考資料

コメント

タイトルとURLをコピーしました