第13章 API与外部服务集成MCP应用
前言
API是连接内外部系统的桥梁。本章展示如何通过MCP为LLM提供与第三方服务(如电商平台、CRM、支付等)集成的能力。
13.1 案例1:电商平台订单管理系统
13.1.1 应用场景
graph TB
A["电商订单管理"] --> B["订单查询"]
A --> C["库存管理"]
A --> D["支付处理"]
A --> E["售后服务"]
F["Claude"] --> F1["智能查询"]
F --> F2["库存提示"]
F --> F3["支付建议"]
F --> F4["退货处理"]
F1 --> B
F2 --> C
F3 --> D
F4 --> E
13.1.2 电商API集成
from typing import Dict, List, Optional
from dataclasses import dataclass
from datetime import datetime
import aiohttp
@dataclass
class Order:
"""订单"""
order_id: str
customer_id: str
status: str
total_amount: float
items: List[Dict]
created_at: datetime
updated_at: datetime
class EcommerceAPIClient:
"""电商API客户端"""
def __init__(self, api_key: str, base_url: str):
self.api_key = api_key
self.base_url = base_url
self.session = None
async def connect(self):
"""建立连接"""
self.session = aiohttp.ClientSession()
async def disconnect(self):
"""断开连接"""
if self.session:
await self.session.close()
async def search_orders(self, customer_id: str = None,
status: str = None, limit: int = 10) -> List[Order]:
"""
搜索订单
Args:
customer_id: 客户ID
status: 订单状态
limit: 返回数限制
Returns:
订单列表
"""
params = {"limit": limit}
if customer_id:
params["customer_id"] = customer_id
if status:
params["status"] = status
async with self.session.get(
f"{self.base_url}/orders",
params=params,
headers={"Authorization": f"Bearer {self.api_key}"}
) as resp:
data = await resp.json()
orders = []
for item in data.get("orders", []):
order = Order(
order_id=item["id"],
customer_id=item["customer_id"],
status=item["status"],
total_amount=item["total"],
items=item["items"],
created_at=datetime.fromisoformat(item["created_at"]),
updated_at=datetime.fromisoformat(item["updated_at"])
)
orders.append(order)
return orders
async def get_order_details(self, order_id: str) -> Dict:
"""获取订单详情"""
async with self.session.get(
f"{self.base_url}/orders/{order_id}",
headers={"Authorization": f"Bearer {self.api_key}"}
) as resp:
return await resp.json()
async def update_order_status(self, order_id: str, status: str) -> bool:
"""更新订单状态"""
async with self.session.patch(
f"{self.base_url}/orders/{order_id}",
json={"status": status},
headers={"Authorization": f"Bearer {self.api_key}"}
) as resp:
return resp.status == 200
async def check_inventory(self, product_id: str) -> Dict:
"""
检查库存
Args:
product_id: 产品ID
Returns:
库存信息
"""
async with self.session.get(
f"{self.base_url}/inventory/{product_id}",
headers={"Authorization": f"Bearer {self.api_key}"}
) as resp:
return await resp.json()
async def process_refund(self, order_id: str, reason: str) -> Dict:
"""
处理退款
Args:
order_id: 订单ID
reason: 退款原因
Returns:
退款结果
"""
async with self.session.post(
f"{self.base_url}/refunds",
json={"order_id": order_id, "reason": reason},
headers={"Authorization": f"Bearer {self.api_key}"}
) as resp:
return await resp.json()
class OrderManagementMCP:
"""订单管理MCP服务"""
def __init__(self, api_client: EcommerceAPIClient):
self.api = api_client
async def find_order(self, order_id: str) -> Dict:
"""查找订单"""
details = await self.api.get_order_details(order_id)
return {
"found": details.get("id") is not None,
"order": {
"id": details.get("id"),
"status": details.get("status"),
"total": details.get("total"),
"items": details.get("items"),
"customer": details.get("customer"),
"created_at": details.get("created_at"),
"updated_at": details.get("updated_at")
} if details.get("id") else None
}
async def search_customer_orders(self, customer_id: str) -> Dict:
"""搜索客户订单"""
orders = await self.api.search_orders(customer_id=customer_id, limit=20)
# 按状态分组
by_status = {}
for order in orders:
if order.status not in by_status:
by_status[order.status] = []
by_status[order.status].append({
"id": order.order_id,
"total": order.total_amount,
"items_count": len(order.items)
})
return {
"customer_id": customer_id,
"total_orders": len(orders),
"by_status": by_status,
"recent_orders": [{
"id": o.order_id,
"total": o.total_amount,
"status": o.status,
"date": o.created_at.isoformat()
} for o in orders[:5]]
}
async def handle_refund_request(self, order_id: str, reason: str) -> Dict:
"""处理退款请求"""
result = await self.api.process_refund(order_id, reason)
return {
"success": result.get("success"),
"refund_id": result.get("refund_id"),
"amount": result.get("amount"),
"status": result.get("status"),
"message": result.get("message")
}
async def check_product_availability(self, product_id: str) -> Dict:
"""检查产品可用性"""
inventory = await self.api.check_inventory(product_id)
return {
"product_id": product_id,
"available": inventory.get("quantity", 0) > 0,
"quantity": inventory.get("quantity"),
"warehouse_locations": inventory.get("locations"),
"next_restock_date": inventory.get("next_restock")
}
13.2 工具定义与集成
class EcommerceMCPServer:
"""电商MCP服务器"""
def __init__(self, order_manager: OrderManagementMCP):
self.orders = order_manager
def get_tools(self) -> List[Dict]:
"""获取工具定义"""
return [
{
"name": "search_orders",
"description": "Search for customer orders",
"inputSchema": {
"type": "object",
"properties": {
"customer_id": {
"type": "string",
"description": "Customer ID to search orders for"
},
"status": {
"type": "string",
"description": "Order status filter (pending/processing/shipped/delivered)",
"enum": ["pending", "processing", "shipped", "delivered"]
}
},
"required": ["customer_id"]
}
},
{
"name": "get_order_details",
"description": "Get detailed information about an order",
"inputSchema": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "Order ID"
}
},
"required": ["order_id"]
}
},
{
"name": "process_refund",
"description": "Process a refund request",
"inputSchema": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "Order ID"
},
"reason": {
"type": "string",
"description": "Refund reason"
}
},
"required": ["order_id", "reason"]
}
}
]
async def call_tool(self, tool_name: str, arguments: Dict) -> str:
"""调用工具"""
import json
try:
if tool_name == "search_orders":
result = await self.orders.search_customer_orders(
arguments["customer_id"]
)
elif tool_name == "get_order_details":
result = await self.orders.find_order(arguments["order_id"])
elif tool_name == "process_refund":
result = await self.orders.handle_refund_request(
arguments["order_id"],
arguments["reason"]
)
else:
return json.dumps({"error": f"Unknown tool: {tool_name}"})
return json.dumps(result, ensure_ascii=False)
except Exception as e:
return json.dumps({"error": str(e)})
13.3 CRM系统增强案例
class CRMAPIClient:
"""CRM API客户端"""
def __init__(self, api_key: str, base_url: str):
self.api_key = api_key
self.base_url = base_url
self.session = None
async def connect(self):
self.session = aiohttp.ClientSession()
async def get_customer_profile(self, customer_id: str) -> Dict:
"""获取客户档案"""
async with self.session.get(
f"{self.base_url}/customers/{customer_id}",
headers={"Authorization": f"Bearer {self.api_key}"}
) as resp:
return await resp.json()
async def get_interaction_history(self, customer_id: str) -> List[Dict]:
"""获取交互历史"""
async with self.session.get(
f"{self.base_url}/customers/{customer_id}/interactions",
headers={"Authorization": f"Bearer {self.api_key}"}
) as resp:
data = await resp.json()
return data.get("interactions", [])
async def create_opportunity(self, customer_id: str, opportunity_data: Dict) -> Dict:
"""创建商机"""
async with self.session.post(
f"{self.base_url}/opportunities",
json={**opportunity_data, "customer_id": customer_id},
headers={"Authorization": f"Bearer {self.api_key}"}
) as resp:
return await resp.json()
async def update_customer_notes(self, customer_id: str, notes: str) -> bool:
"""更新客户备注"""
async with self.session.patch(
f"{self.base_url}/customers/{customer_id}",
json={"notes": notes},
headers={"Authorization": f"Bearer {self.api_key}"}
) as resp:
return resp.status == 200
13.4 高级功能:限流与重试机制
from enum import Enum
import asyncio
from typing import Callable
class RetryStrategy:
"""重试策略"""
def __init__(self, max_retries: int = 3, backoff_factor: float = 2.0):
self.max_retries = max_retries
self.backoff_factor = backoff_factor
async def execute_with_retry(self, func: Callable, *args, **kwargs):
"""
执行函数并进行重试
Args:
func: 要执行的函数
*args: 位置参数
**kwargs: 关键字参数
Returns:
函数执行结果
"""
for attempt in range(self.max_retries):
try:
return await func(*args, **kwargs)
except Exception as e:
if attempt == self.max_retries - 1:
raise
wait_time = self.backoff_factor ** attempt
await asyncio.sleep(wait_time)
class RateLimiter:
"""速率限制器"""
def __init__(self, requests_per_minute: int = 60):
self.requests_per_minute = requests_per_minute
self.request_times: List[float] = []
async def wait_if_needed(self):
"""
如果超过限制则等待
"""
import time
now = time.time()
one_minute_ago = now - 60
# 移除一分钟前的请求记录
self.request_times = [t for t in self.request_times if t > one_minute_ago]
if len(self.request_times) >= self.requests_per_minute:
# 计算需要等待的时间
oldest_request = self.request_times[0]
wait_time = 60 - (now - oldest_request)
if wait_time > 0:
await asyncio.sleep(wait_time)
self.request_times = []
self.request_times.append(now)
class EnhancedEcommerceAPIClient(EcommerceAPIClient):
"""增强的电商API客户端"""
def __init__(self, api_key: str, base_url: str,
rate_limit: int = 100):
super().__init__(api_key, base_url)
self.retry_strategy = RetryStrategy()
self.rate_limiter = RateLimiter(rate_limit)
self.request_cache: Dict[str, Tuple[Dict, float]] = {}
self.cache_ttl = 300 # 5分钟缓存
async def search_orders_safe(self, customer_id: str = None,
status: str = None) -> List[Order]:
"""
安全的搜索订单(带重试和限流)
"""
await self.rate_limiter.wait_if_needed()
return await self.retry_strategy.execute_with_retry(
self.search_orders,
customer_id=customer_id,
status=status
)
def _get_cache_key(self, method: str, *args) -> str:
"""生成缓存键"""
import hashlib
key = f"{method}_{' '.join(str(a) for a in args)}"
return hashlib.md5(key.encode()).hexdigest()
async def get_cached_result(self, method: str, *args, **kwargs):
"""获取缓存结果"""
import time
cache_key = self._get_cache_key(method, *args)
if cache_key in self.request_cache:
result, timestamp = self.request_cache[cache_key]
if time.time() - timestamp < self.cache_ttl:
return result
else:
del self.request_cache[cache_key]
return None
13.5 完整的CRM系统集成
class EnhancedCRMAPIClient(CRMAPIClient):
"""增强的CRM客户端"""
async def get_customer_analysis(self, customer_id: str) -> Dict:
"""
获取客户综合分析
Args:
customer_id: 客户ID
Returns:
客户分析结果
"""
# 获取基础信息
profile = await self.get_customer_profile(customer_id)
interactions = await self.get_interaction_history(customer_id)
# 分析交互模式
interaction_analysis = self._analyze_interactions(interactions)
# 生成建议
recommendations = self._generate_recommendations(profile, interaction_analysis)
return {
"customer_id": customer_id,
"profile": profile,
"interaction_analysis": interaction_analysis,
"recommendations": recommendations,
"health_score": self._calculate_health_score(profile, interaction_analysis)
}
def _analyze_interactions(self, interactions: List[Dict]) -> Dict:
"""分析交互"""
if not interactions:
return {"count": 0, "types": {}, "last_interaction": None}
types = {}
for interaction in interactions:
itype = interaction.get("type", "unknown")
types[itype] = types.get(itype, 0) + 1
return {
"count": len(interactions),
"types": types,
"last_interaction": interactions[-1].get("timestamp"),
"engagement_level": "high" if len(interactions) > 5 else "medium" if len(interactions) > 2 else "low"
}
def _generate_recommendations(self, profile: Dict,
analysis: Dict) -> List[str]:
"""生成建议"""
recommendations = []
if analysis["engagement_level"] == "low":
recommendations.append("Schedule follow-up call")
recommendations.append("Send personalized offer")
if profile.get("annual_value", 0) > 100000:
recommendations.append("Assign dedicated account manager")
return recommendations
def _calculate_health_score(self, profile: Dict,
analysis: Dict) -> float:
"""计算健康评分"""
score = 50.0
# 基于交互频率
if analysis.get("engagement_level") == "high":
score += 30
elif analysis.get("engagement_level") == "medium":
score += 15
# 基于交易金额
if profile.get("annual_value", 0) > 100000:
score += 20
return min(score, 100.0)
13.6 工作流程与业务场景
class OrderManagementWorkflow:
"""订单管理工作流"""
def __init__(self, order_manager: OrderManagementMCP,
crm_client: EnhancedCRMAPIClient):
self.orders = order_manager
self.crm = crm_client
async def handle_customer_inquiry(self, customer_id: str,
inquiry_type: str) -> Dict:
"""
处理客户询问的完整工作流
Args:
customer_id: 客户ID
inquiry_type: 询问类型
Returns:
处理结果
"""
workflow_result = {
"customer_id": customer_id,
"steps": [],
"resolution": None
}
# 第1步:获取客户订单
workflow_result["steps"].append({
"name": "Fetch Customer Orders",
"status": "running"
})
orders = await self.orders.search_customer_orders(customer_id)
workflow_result["steps"][-1]["status"] = "completed"
workflow_result["steps"][-1]["data"] = orders
# 第2步:获取客户分析
workflow_result["steps"].append({
"name": "Analyze Customer Profile",
"status": "running"
})
analysis = await self.crm.get_customer_analysis(customer_id)
workflow_result["steps"][-1]["status"] = "completed"
workflow_result["steps"][-1]["data"] = analysis
# 第3步:根据询问类型处理
workflow_result["steps"].append({
"name": f"Handle {inquiry_type}",
"status": "running"
})
if inquiry_type == "refund":
# 找最近的订单
recent_order = orders.get("recent_orders", [{}])[0]
resolution = await self.orders.handle_refund_request(
recent_order.get("id"),
"Customer request"
)
elif inquiry_type == "product_info":
# 检查库存
product_id = orders.get("recent_orders", [{}])[0].get("id")
resolution = await self.orders.check_product_availability(product_id)
else:
resolution = {"status": "Unknown inquiry type"}
workflow_result["steps"][-1]["status"] = "completed"
workflow_result["resolution"] = resolution
# 第4步:生成后续行动
workflow_result["steps"].append({
"name": "Generate Follow-up Actions",
"status": "completed",
"data": analysis.get("recommendations", [])
})
return workflow_result
async def process_bulk_orders(self, customer_ids: List[str]) -> Dict:
"""
批量处理订单
Args:
customer_ids: 客户ID列表
Returns:
批量处理结果
"""
results = {
"total": len(customer_ids),
"successful": 0,
"failed": 0,
"details": []
}
for customer_id in customer_ids:
try:
workflow = await self.handle_customer_inquiry(
customer_id,
"status_check"
)
results["successful"] += 1
results["details"].append({
"customer_id": customer_id,
"status": "completed"
})
except Exception as e:
results["failed"] += 1
results["details"].append({
"customer_id": customer_id,
"status": "failed",
"error": str(e)
})
return results
13.7 部署架构与安全
graph TB
A["Claude Desktop"] -->|MCP| B["API集成服务器"]
B --> C["请求管理"]
C --> C1["限流器"]
C --> C2["重试管理"]
C --> C3["缓存层"]
B --> D["API网关"]
D --> E["电商API"]
D --> F["CRM API"]
D --> G["支付API"]
B --> H["安全管理"]
H --> H1["API密钥管理"]
H --> H2["加密通道"]
H --> H3["审计日志"]
13.7.1 安全实现
class APISecurityManager:
"""API安全管理"""
def __init__(self):
self.api_keys: Dict[str, Dict] = {}
self.audit_log: List[Dict] = []
def register_api_key(self, service: str, key: str,
rotation_days: int = 90) -> Dict:
"""
注册API密钥
Args:
service: 服务名称
key: API密钥
rotation_days: 轮换周期(天)
Returns:
密钥信息
"""
from datetime import datetime, timedelta
import hashlib
key_hash = hashlib.sha256(key.encode()).hexdigest()
key_info = {
"service": service,
"key_hash": key_hash,
"created_at": datetime.now().isoformat(),
"expires_at": (datetime.now() + timedelta(days=rotation_days)).isoformat(),
"status": "active"
}
self.api_keys[service] = key_info
self._log_audit("api_key_registered", {"service": service})
return key_info
def validate_api_key(self, service: str, key: str) -> bool:
"""验证API密钥"""
import hashlib
from datetime import datetime
if service not in self.api_keys:
return False
key_info = self.api_keys[service]
# 检查过期
expires_at = datetime.fromisoformat(key_info["expires_at"])
if datetime.now() > expires_at:
self._log_audit("api_key_expired", {"service": service})
return False
# 验证哈希
key_hash = hashlib.sha256(key.encode()).hexdigest()
if key_hash != key_info["key_hash"]:
self._log_audit("invalid_api_key", {"service": service})
return False
return True
def _log_audit(self, action: str, details: Dict):
"""记录审计日志"""
from datetime import datetime
self.audit_log.append({
"timestamp": datetime.now().isoformat(),
"action": action,
"details": details
})
13.8 错误处理与恢复
class APIErrorHandler:
"""API错误处理"""
@staticmethod
def handle_error(error: Exception) -> Dict:
"""
处理API错误
Args:
error: 错误对象
Returns:
错误信息
"""
error_handlers = {
"TimeoutError": APIErrorHandler._handle_timeout,
"ConnectionError": APIErrorHandler._handle_connection,
"ValueError": APIErrorHandler._handle_validation,
}
error_type = type(error).__name__
handler = error_handlers.get(error_type, APIErrorHandler._handle_generic)
return handler(error)
@staticmethod
def _handle_timeout(error: Exception) -> Dict:
return {
"error_type": "timeout",
"message": "API request timed out",
"suggestion": "Retry with exponential backoff",
"retry_after_seconds": 30
}
@staticmethod
def _handle_connection(error: Exception) -> Dict:
return {
"error_type": "connection",
"message": "Failed to connect to API",
"suggestion": "Check network connectivity and API endpoint",
"retry_after_seconds": 60
}
@staticmethod
def _handle_validation(error: Exception) -> Dict:
return {
"error_type": "validation",
"message": "Invalid request parameters",
"suggestion": "Review request schema and try again",
"retry_after_seconds": 0
}
@staticmethod
def _handle_generic(error: Exception) -> Dict:
return {
"error_type": "generic",
"message": str(error),
"suggestion": "Contact support if problem persists",
"retry_after_seconds": 30
}
13.9 完整集成示例
async def main():
"""完整使用示例"""
# 初始化
ecommerce_client = EnhancedEcommerceAPIClient(
api_key="your_api_key",
base_url="https://api.ecommerce.com",
rate_limit=100
)
crm_client = EnhancedCRMAPIClient(
api_key="your_crm_key",
base_url="https://api.crm.com"
)
await ecommerce_client.connect()
await crm_client.connect()
# 初始化工作流
order_manager = OrderManagementMCP(ecommerce_client)
workflow = OrderManagementWorkflow(order_manager, crm_client)
security = APISecurityManager()
# 注册API密钥
security.register_api_key("ecommerce", "your_api_key")
security.register_api_key("crm", "your_crm_key")
# 处理客户询问
print("🔄 Processing customer inquiry...")
result = await workflow.handle_customer_inquiry("CUST001", "refund")
print(f"✅ Resolution: {result['resolution']}")
# 批量处理
print("🔄 Processing bulk orders...")
bulk_result = await workflow.process_bulk_orders([
"CUST001", "CUST002", "CUST003"
])
print(f"✅ Successful: {bulk_result['successful']}/{bulk_result['total']}")
# 清理
await ecommerce_client.disconnect()
await crm_client.disconnect()
本章总结
| 关键点 | 说明 |
|---|---|
| API集成 | 通过HTTP/REST访问第三方服务 |
| 异步处理 | aiohttp进行高效的异步API调用 |
| 错误处理 | 完善的异常处理和重试机制 |
| 数据转换 | 将API响应转换为结构化数据 |
| 权限管理 | API密钥和认证 |
| 缓存策略 | 热点数据缓存优化性能 |
常见问题
Q1: 如何处理API限流? A: 实施令牌桶算法或指数退避重试,遵守API速率限制。
Q2: 如何保护API密钥? A: 使用环境变量、密钥管理服务,不要硬编码密钥。
Q3: 如何处理API超时? A: 设置合理的超时时间,实施自动重试和降级方案。
Q4: 如何支持多个API版本? A: 通过适配器模式或版本路由支持多个API版本。
Q5: 如何监控API集成健康状态? A: 定期health check,记录API调用指标,设置告警。
下一章预告:第14章将讲述知识库与信息管理MCP应用!