私は以前/ECサイトのAIカスタマーサービスシステムを構築していた際、LangGraphで外部APIを呼び出すたびに「認証情報をどう管理すべきか」という壁にぶつかりました。社内CRMへのアクセス、配送追跡システムの統合、カスタマーサポートチケットの作成——これらをすべてLangGraphのTool Callingで実現したい。しかし、ベンダーAPIのキーがソースコードに露出している现状は明らかに危険です。本稿では、MCP(Model Context Protocol)ゲートウェイの役割と、代替アーキテクチャの選択肢を実務観点から整理します。

なぜLangGraphのTool Callingは企業環境では危険なのか

LangGraphはAgentアーキテクチャの実装に優れていますが、標準設定のまま外部ツールを呼び出す場合、いくつかの本質的課題が存在します。

典型的な脆弱性の例

# ❌ 危険: APIキーが直接露出
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="gpt-4.1",
    api_key="sk-xxxxx...",  # APIキーがここに露出
    base_url="https://api.holysheep.ai/v1"  # HolySheep AI使用
)

tools = [
    {
        "name": "query_inventory",
        "description": "在庫確認",
        "function": lambda product_id: requests.get(
            f"https://internal-corp-api.com/inventory/{product_id}",
            headers={"Authorization": "Bearer internal-key-xxx"}
        ).json()
    }
]

agent = create_react_agent(llm, tools)

LLMがプロンプトインジェクション攻撃を受けると、内部APIキーが流出する可能性

上記のコードでは、LLMへのプロンプトインジェクション攻撃成功時、認証情報が外部に漏れるリスクがあります。また、複数の社内ツール调用時に認証情報を分散管理することは運用の複雑さを増大させます。

MCPゲートウェイを導入する3つのパターン

MCPゲートウェイは、LangGraph Agentと企業内部ツールの間に立つ「認証・認可の門番」として機能します。導入パターンは大きく3つに分類されます。

パターン1: MCPサーバーとしてのLangServe

# ✅ MCPゲートウェイ兼任: LangServeで 안전한 ツール公開

server.py

from fastapi import FastAPI, HTTPException from pydantic import BaseModel from langserve import add_routes from langchain_core.tools import tool from langchain_holysheep import HolySheepChatOpenAI # 成本節約 import os app = FastAPI(title="企業ツールMCPゲートウェイ")

環境変数で認証情報を管理(Git等にはコミットしない)

CORP_API_KEY = os.environ["CORP_API_KEY"] HOLYSHEEP_API_KEY = os.environ["HOLYSHEEP_API_KEY"] llm = HolySheepChatOpenAI( model="deepseek-chat", api_key=HOLYSHEEP_API_KEY, base_url="https://api.holysheep.ai/v1", temperature=0.3 ) @tool def query_inventory(product_id: str, warehouse: str = "main") -> dict: """企業の在庫管理系统にクエリを送信(認証済み)""" import requests response = requests.get( f"https://internal-corp-api.com/inventory/{product_id}", params={"warehouse": warehouse}, headers={ "Authorization": f"Bearer {CORP_API_KEY}", "X-Request-Source": "mcp-gateway" }, timeout=5 ) if response.status_code != 200: raise HTTPException(status_code=response.status_code, detail="在庫APIエラー") return response.json() @tool def create_support_ticket(customer_id: str, issue: str, priority: str = "normal") -> dict: """サポートチケットをCRMに作成(監査ログ出力)""" import requests import logging logging.info(f"[AUDIT] ticket_create: customer={customer_id}, priority={priority}") response = requests.post( "https://internal-corp-api.com/tickets", json={"customer_id": customer_id, "issue": issue, "priority": priority}, headers={"Authorization": f"Bearer {CORP_API_KEY}"} ) return response.json()

LangGraph AgentをMCPツールとして公開

from langgraph.prebuilt import create_react_agent agent = create_react_agent(llm, [query_inventory, create_support_ticket]) add_routes(app, agent, path="/agent", enabled_endpoints=["invoke", "stream"]) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8080)

このパターンでは、LangServe経由でLangGraph AgentをMCPプロトコル対応のツールとして公開します。認証情報(CORP_API_KEY)はサーバー側で環境変数として管理するため、LLMに露出しません。

パターン2: 専用MCPゲートウェイ(Recommended for Enterprise)

# ✅ 専用MCPゲートウェイ: 認証・認可・レート制限を集中管理

mcp_gateway.py

from fastapi import FastAPI, Header, HTTPException, Request from pydantic import BaseModel from typing import Optional import hashlib import hmac import time app = FastAPI(title="Enterprise MCP Gateway")

事前共有鍵によるリクエスト署名(LLMへの直接アクセスを 차단)

SHARED_SECRET = os.environ["MCP_SHARED_SECRET"] class ToolRequest(BaseModel): tool_name: str parameters: dict session_id: str user_context: Optional[dict] = None @app.post("/mcp/invoke") async def invoke_tool( request: ToolRequest, authorization: str = Header(None) ): # HMAC署名検証 if not verify_signature(request, authorization): raise HTTPException(status_code=401, detail="無効な署名") # レート制限チェック(HolySheep AI ¥1=$1 で成本最適化) if not check_rate_limit(request.session_id): raise HTTPException(status_code=429, detail="レート制限超過") # ツールディスパッチ(権限チェック付き) allowed_tools = get_user_permissions(request.session_id) if request.tool_name not in allowed_tools: raise HTTPException(status_code=403, detail="ツール利用権限なし") # 監査ログ log_tool_usage(request) return await dispatch_tool(request.tool_name, request.parameters) def verify_signature(req: ToolRequest, auth: str) -> bool: """リクエスト改ざん検知""" expected = hmac.new( SHARED_SECRET.encode(), f"{req.session_id}:{req.tool_name}:{time.time()//60}".encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(auth, f"Bearer {expected}")

クライアントサイド: HolySheep AI LangGraph Agent

client_agent.py

from langchain_core.tools import StructuredTool from langgraph.prebuilt import create_react_agent from langchain_holysheep import HolySheepChatOpenAI llm = HolySheepChatOpenAI( model="gpt-4.1", # $8/MTok(他のベンダー比85%節約) api_key=os.environ["HOLYSHEEP_API_KEY"], base_url="https://api.holysheep.ai/v1" ) def mcp_tool(tool_name: str, parameters: dict): """MCPゲートウェイ経由でツール呼び出し""" import httpx import hmac import time session = parameters.pop("_session_id", "default") payload = {"tool_name": tool_name, "parameters": parameters, "session_id": session} # 署名生成 signature = hmac.new( os.environ["MCP_SHARED_SECRET"].encode(), f"{session}:{tool_name}:{time.time()//60}".encode(), hashlib.sha256 ).hexdigest() response = httpx.post( "https://mcp-gateway.internal.com/mcp/invoke", json=payload, headers={"Authorization": f"Bearer {signature}"}, timeout=30 ) return response.json()

MCPツール定義

inventory_tool = StructuredTool.from_function( func=lambda product_id, warehouse="main": mcp_tool("query_inventory", {"product_id": product_id, "warehouse": warehouse}), name="query_inventory", description="社内在庫システムを安全にクエリ" ) ticket_tool = StructuredTool.from_function( func=lambda customer_id, issue, priority="normal": mcp_tool("create_support_ticket", {"customer_id": customer_id, "issue": issue, "priority": priority}), name="create_support_ticket", description="CRMにサポートチケットを作成" ) agent = create_react_agent(llm, [inventory_tool, ticket_tool])

HolySheep AIをLangGraph Enterprise環境に統合するメリット

私は複数の本番環境を運用していますが、HolySheep AIへの登録後はコスト構造が大きく改善されました。具体的な数値を示すと、GPT-4.1は$8/MTokですがDeepSeek V3.2は$0.42/MTokと80%以上低成本です。ECサイトのAI客服で月500万トークンを処理する場合、月額約$4,000が$200近くに削減されます。

また、WeChat Pay・Alipayに対応しているため、中国本土の開発チームとの決済もスムーズです。登録時に無料クレジットが付与されるのも、試運用期間に便利です。レイテンシは50ms未満を保証しており、リアルタイム性が求められる客服シナリオでも安心感があります。

MCPゲートウェイ不要の場合:いつ安全と判断できるか

MCPゲートウェイは銀の弾丸ではありません。以下の場合、導入コストに見合わない可能性があります。

# ✅ Read-only外部APIのみの場合:MCP不要で安全的
from langgraph.prebuilt import create_react_agent
from langchain_holysheep import HolySheepChatOpenAI

llm = HolySheepChatOpenAI(
    model="gemini-2.5-flash",  # $2.50/MTok、成本重視
    api_key=os.environ["HOLYSHEEP_API_KEY"],
    base_url="https://api.holysheep.ai/v1"
)

読み取り専用のPublic APIのみ呼び出す場合

public_tools = [ { "name": "get_weather", "description": "天気情報取得", "function": lambda city: requests.get( f"https://api.open-meteo.com/v1/forecast", params={"city": city, "current_weather": True} ).json() }, { "name": "get_exchange_rate", "description": "為替レート取得", "function": lambda from_cur, to_cur: requests.get( f"https://api.exchangerate.host/latest", params={"base": from_cur, "symbols": to_cur} ).json() } ] agent = create_react_agent(llm, public_tools)

認証情報不要、LLMへの露出リスクも低い

よくあるエラーと対処法

エラー1: MCP_gateway_timeout - ツール呼び出しがタイムアウトする

# 問題: 内部APIの応答遅延がLangGraphのデフォルトtimeout超過

LangGraphデフォルト: 通常30秒程度

解決: timeout設定とリトライロジックを追加

from tenacity import retry, stop_after_attempt, wait_exponential @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=10)) async def resilient_tool_call(tool_name: str, params: dict): try: async with httpx.AsyncClient() as client: response = await client.post( f"https://mcp-gateway.internal.com/mcp/invoke", json={"tool_name": tool_name, "parameters": params, "session_id": "default"}, timeout=httpx.Timeout(60.0, connect=10.0) # 合計60秒timeout ) response.raise_for_status() return response.json() except httpx.TimeoutException as e: # フォールバック: 直接API呼び出し(認証情報をServer Sideで保持) return await fallback_direct_call(tool_name, params)

エラー2: authentication_realm_mismatch - 認証Realmの不一致

# 問題: LangGraph AgentとMCP Gatewayで認証情報が異なる

症状: 401 Unauthorized が不定期発生

解決: セッションキーを統一管理

import redis redis_client = redis.from_url(os.environ["REDIS_URL"]) def get_auth_token(session_id: str) -> str: """Redisから有効な認証トークンを取得""" token = redis_client.get(f"auth:{session_id}") if token: return token.decode() # 新規トークン発行(OAuth2 Client Credentials Flow) token = acquire_oauth_token( client_id=os.environ["CORP_CLIENT_ID"], client_secret=os.environ["CORP_CLIENT_SECRET"], token_url="https://auth.internal.com/oauth/token" ) redis_client.setex(f"auth:{session_id}", 3600, token) # 1時間有効 return token

Agent初期化時にセッションを共有

agent = create_react_agent(llm, tools, config={"configurable": {"session_id": session_id}})

エラー3: circular_dependency_detected - LangGraph内で無限ループ

# 問題: あるツールが別のツールを呼び出し、それが元のツールを呼び出す

例: query_inventory → check_stock_level → query_inventory → ...

解決: ツール呼び出し深度を制限

MAX_TOOL_CALL_DEPTH = 5 from langgraph.graph import StateGraph, END from langgraph.prebuilt import ToolNode from typing import TypedDict class AgentState(TypedDict): messages: list tool_call_depth: int def should_continue(state: AgentState) -> str: if state["tool_call_depth"] >= MAX_TOOL_CALL_DEPTH: return END return "tools" graph = StateGraph(AgentState) graph.add_node("agent", agent_node) graph.add_node("tools", ToolNode(tools)) graph.add_edge("__start__", "agent") graph.add_conditional_edges("agent", should_continue, {"tools": "tools", END: END}) graph.add_edge("tools", "agent") compiled = graph.compile()

深度超過時は警告とともに処理終了

if state["tool_call_depth"] >= MAX_TOOL_CALL_DEPTH: logger.warning(f"[SECURITY] ツール呼び出し深度超過: {state['tool_call_depth']}") return "ツール呼び出し上限に達しました。管理者にお問い合わせください。"

エラー4: prompt_injection_detected - インジェクション攻撃

# 問題: ユーザーがプロンプト内に悪意あるコマンドを挿入

解決: MCPゲートウェイで入力サニタイズ

import re @app.post("/mcp/invoke") async def safe_invoke(request: ToolRequest): # パラメータ内の悪意あるパターンを検出してブロック dangerous_patterns = [ r"ignore previous instructions", r"ignore all previous", r"disregard.*instruction", r"--ignore", r"&#", r"