Skip to main content
Glama
OUTPUTSCHEMA_GUIDE.md10.6 kB
# OutputSchema 使用指南 ## 📋 概述 本指南介绍如何在 Awesome-MCP-Scaffold 中使用 MCP SDK v1.11.0 的 `outputSchema` 功能,为工具提供结构化输出支持。 ## 🎯 什么是 OutputSchema `outputSchema` 是 MCP 协议的一个新特性,允许工具定义其返回值的结构化模式。这提供了: - **类型安全**:确保工具返回预期格式的数据 - **自动验证**:MCP SDK 自动验证返回值符合定义的模式 - **更好的集成**:客户端可以可靠地解析和使用工具返回的数据 - **向后兼容**:同时提供结构化和文本格式的输出 ## 🔧 快速开始 ### 1. 定义响应模型 ```python # server/models/responses.py from pydantic import BaseModel, Field from datetime import datetime class CalculationResult(BaseModel): """计算结果模型""" success: bool = Field(description="操作是否成功") timestamp: datetime = Field(default_factory=datetime.now, description="操作时间") result: float = Field(description="计算结果") expression: str = Field(description="计算表达式") operation: str = Field(description="操作类型") ``` ### 2. 创建结构化工具 ```python # server/tools/calculator.py from ..models.responses import CalculationResult @mcp.tool(title="Add Numbers", description="Add two numbers together") def add(a: float, b: float) -> CalculationResult: """Add two numbers and return structured result.""" result = a + b return CalculationResult( success=True, result=result, expression=f"{a} + {b}", operation="addition" ) ``` ### 3. 自动 Schema 生成 MCP SDK 会自动从返回类型注解生成 `outputSchema`: ```json { "name": "add", "title": "Add Numbers", "description": "Add two numbers together", "outputSchema": { "type": "object", "properties": { "success": {"type": "boolean", "description": "操作是否成功"}, "timestamp": {"type": "string", "format": "date-time", "description": "操作时间"}, "result": {"type": "number", "description": "计算结果"}, "expression": {"type": "string", "description": "计算表达式"}, "operation": {"type": "string", "description": "操作类型"} }, "required": ["success", "timestamp", "result", "expression", "operation"] } } ``` ## 📚 内置响应模型 脚手架提供了一套标准的响应模型: ### 基础模型 ```python from server.models.responses import BaseToolResponse class BaseToolResponse(BaseModel): """所有工具响应的基类""" success: bool = Field(description="操作是否成功") timestamp: datetime = Field(default_factory=datetime.now, description="操作时间") ``` ### 计算器模型 ```python from server.models.responses import CalculationResult, BMIResult, StatisticsResult # 基础计算结果 CalculationResult( success=True, result=42.0, expression="6 * 7", operation="multiplication" ) # BMI 计算结果 BMIResult( success=True, bmi=22.86, category="Normal weight", weight_kg=70.0, height_m=1.75 ) # 统计分析结果 StatisticsResult( success=True, average=15.5, count=4, sum=62.0, minimum=10.0, maximum=20.0 ) ``` ### 文本处理模型 ```python from server.models.responses import TextAnalysisResult, CaseConversionResult, ExtractionResult # 文本分析结果 TextAnalysisResult( success=True, words=50, characters=300, characters_no_spaces=250, lines=5 ) # 大小写转换结果 CaseConversionResult( success=True, original="Hello World", converted="HELLO WORLD", case_type="upper" ) # 文本提取结果 ExtractionResult( success=True, matches=["user@example.com", "admin@domain.org"], count=2, pattern="email" ) ``` ### 文件操作模型 ```python from server.models.responses import FileOperationResult, FileInfoResult, DirectoryResult # 文件操作结果 FileOperationResult( success=True, message="File written successfully", file_path="data/example.txt", size_bytes=1024, operation="write" ) # 文件信息结果 FileInfoResult( success=True, path="data/file.txt", name="file.txt", type="file", size_bytes=2048, created=1640995200.0, modified=1640995300.0, exists=True ) # 目录列表结果 DirectoryResult( success=True, path="data/", files=["file1.txt", "file2.json"], directories=["subdir1", "subdir2"], total_files=2, total_directories=2 ) ``` ## 🛠️ 自定义响应模型 ### 1. 创建新模型 ```python # server/models/responses.py class WeatherResult(BaseToolResponse): """天气查询结果""" temperature: float = Field(description="温度(摄氏度)") humidity: float = Field(description="湿度(百分比)", ge=0, le=100) condition: str = Field(description="天气状况") location: str = Field(description="查询位置") wind_speed: Optional[float] = Field(None, description="风速(km/h)") ``` ### 2. 使用自定义模型 ```python @mcp.tool(title="Get Weather", description="Get current weather information") def get_weather(city: str) -> WeatherResult: """Get weather information for a city.""" # 实际的天气 API 调用逻辑 weather_data = fetch_weather_api(city) return WeatherResult( success=True, temperature=weather_data["temp"], humidity=weather_data["humidity"], condition=weather_data["condition"], location=city, wind_speed=weather_data.get("wind_speed") ) ``` ## 🔄 迁移现有工具 ### 原始工具(返回 dict) ```python @mcp.tool(title="Old Tool", description="Legacy tool") def old_tool(param: str) -> dict: return { "result": "some value", "status": "ok" } ``` ### 迁移后工具(结构化输出) ```python from ..models.responses import SimpleResult @mcp.tool(title="New Tool", description="Modernized tool") def new_tool(param: str) -> SimpleResult: return SimpleResult( success=True, result="some value", details="Operation completed successfully" ) ``` ## 🧪 测试结构化输出 ### 1. 验证 Schema 生成 ```python async def test_tool_output_schema(): tools = await client.list_tools() tool = next(t for t in tools.tools if t.name == "add") assert tool.outputSchema is not None assert tool.outputSchema["type"] == "object" assert "result" in tool.outputSchema["properties"] ``` ### 2. 验证结构化输出 ```python async def test_structured_output(): result = await client.call_tool("add", {"a": 5, "b": 3}) # 验证结构化内容存在 if hasattr(result, 'structuredContent'): assert result.structuredContent["success"] is True assert result.structuredContent["result"] == 8.0 ``` ### 3. 验证向后兼容性 ```python async def test_backward_compatibility(): result = await client.call_tool("add", {"a": 10, "b": 20}) # 验证传统 content 仍然存在 assert hasattr(result, 'content') assert len(result.content) > 0 ``` ## 📊 响应格式示例 ### MCP 协议响应 ```json { "jsonrpc": "2.0", "id": 1, "result": { "content": [ { "type": "text", "text": "{\"success\": true, \"timestamp\": \"2025-01-01T12:00:00\", \"result\": 8.0, \"expression\": \"5 + 3\", \"operation\": \"addition\"}" } ], "structuredContent": { "success": true, "timestamp": "2025-01-01T12:00:00", "result": 8.0, "expression": "5 + 3", "operation": "addition" } } } ``` ### 客户端使用 ```python # 使用结构化内容(推荐) if hasattr(result, 'structuredContent'): data = result.structuredContent print(f"Result: {data['result']}") print(f"Operation: {data['operation']}") # 使用文本内容(向后兼容) else: text = result.content[0].text data = json.loads(text) print(f"Result: {data['result']}") ``` ## 🚨 最佳实践 ### 1. 模型设计 - **继承基类**:所有响应模型都应继承 `BaseToolResponse` - **描述完整**:使用 `Field(description=...)` 提供清晰的字段说明 - **类型安全**:使用适当的类型约束(如 `ge=0` 表示大于等于0) - **可选字段**:使用 `Optional` 和默认值处理可选数据 ### 2. 错误处理 ```python @mcp.tool(title="Safe Tool", description="Tool with error handling") def safe_tool(value: int) -> Union[CalculationResult, ErrorResult]: try: if value < 0: raise ValueError("Value must be positive") result = complex_calculation(value) return CalculationResult( success=True, result=result, expression=f"calc({value})", operation="complex_calculation" ) except Exception as e: return ErrorResult( success=False, error_type=type(e).__name__, error_message=str(e), error_code="CALC_ERROR" ) ``` ### 3. 版本兼容性 - **渐进式升级**:逐步迁移现有工具到结构化输出 - **保持向后兼容**:确保现有客户端仍能正常工作 - **文档更新**:及时更新 API 文档和示例 ## 🔧 开发工具 ### 1. 模型验证器 ```python # scripts/validate_schemas.py def validate_tool_schemas(): """验证所有工具的 outputSchema""" for tool in get_all_tools(): if hasattr(tool, 'outputSchema'): validate_json_schema(tool.outputSchema) print(f"✅ {tool.name} schema is valid") ``` ### 2. Schema 生成器 ```python # scripts/generate_docs.py def generate_schema_docs(): """生成 outputSchema 文档""" for tool in get_all_tools(): if hasattr(tool, 'outputSchema'): generate_markdown_doc(tool.name, tool.outputSchema) ``` ## 🚀 后续计划 ### 短期目标 - [ ] 完成所有现有工具的迁移 - [ ] 添加更多响应模型类型 - [ ] 完善测试覆盖率 ### 长期目标 - [ ] 自动化模型生成工具 - [ ] 可视化 Schema 编辑器 - [ ] 客户端 SDK 生成 ## 📞 支持 如果在使用 outputSchema 功能时遇到问题: 1. 查看 [测试文件](../tests/test_output_schema.py) 获取使用示例 2. 参考 [规划文档](OUTPUTSCHEMA_UPGRADE_PLAN.md) 了解实现细节 3. 提交 [GitHub Issue](https://github.com/WW-AI-Lab/Awesome-MCP-Scaffold/issues) 报告问题 --- **💡 提示**:outputSchema 功能完全向后兼容,现有的工具和客户端无需任何修改即可继续正常工作。

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/WW-AI-Lab/Awesome-MCP-Scaffold'

If you have feedback or need assistance with the MCP directory API, please join our Discord server