在构建复杂的AI应用时,与用户进行有效的交互和提供实时反馈至关重要。MCP框架的上下文(Context)系统提供了强大的机制,使工具能够在执行过程中与客户端进行双向通信。本文将深入探讨MCP的上下文系统,介绍如何使用Context对象进行日志记录、进度报告、资源访问和错误处理。通过这些示例,你将了解如何开发更加交互式和用户友好的AI工具,提升整体用户体验。
上下文系统简介
MCP的上下文系统允许工具在执行过程中与客户端进行实时通信,而不仅仅是在执行完成后返回结果。上下文对象(Context)提供了多种方法,使工具能够:
- 发送日志消息:向客户端发送不同级别的日志信息
- 报告执行进度:通知客户端当前的执行进度
- 访问资源内容:直接从工具代码中读取资源
- 处理错误情况:在出现问题时提供详细的错误信息
这些功能使得工具能够提供更加丰富的反馈,特别是在执行长时间运行的任务时。
上下文功能与实现
1. 日志记录
上下文对象提供了多个日志级别的方法,用于向客户端发送不同重要性的消息:
@mcp.tool()
async def tool_with_logging(ctx: Context):
"""演示如何使用Context进行日志记录"""
await ctx.debug("这是一条调试消息")
await ctx.info("这是一条信息消息")
await ctx.warning("这是一条警告消息")
await ctx.error("这是一条错误消息")
return "日志记录完成"
这些日志消息会实时发送到客户端,使用户能够了解工具的执行状态和可能的问题。
2. 进度报告
对于处理多个项目的工具,上下文对象的report_progress
方法可以用来报告当前进度:
@mcp.tool()
async def process_files(files: List[str], ctx: Context):
"""演示如何使用Context报告进度"""
total_files = len(files)
for i, file in enumerate(files, 1):
# 报告当前进度
await ctx.report_progress(i, total_files)
# 模拟文件处理
await ctx.info(f"正在处理文件: {file}")
# 这里可以添加实际的文件处理逻辑
return f"成功处理了 {total_files} 个文件"
进度报告使用户能够了解长时间运行任务的完成情况,提高用户体验。
3. 资源访问
上下文对象的read_resource
方法允许工具直接读取资源内容:
@mcp.tool()
async def analyze_file(file_uri: str, ctx: Context):
"""演示如何使用Context访问资源"""
try:
# 读取资源内容
content_iter = await ctx.read_resource(file_uri)
content_list = list(content_iter)
# 分析内容
content_length = len(content_list)
await ctx.info(f"文件内容长度: {content_length} 行")
# 返回分析结果
return {
"file_uri": file_uri,
"content_length": content_length,
"first_line": content_list[0] if content_list else None
}
except Exception as e:
await ctx.error(f"分析文件时出错: {str(e)}")
raise
这使得工具能够直接访问和处理资源内容,而不需要通过额外的API调用。
4. 组合使用
在实际应用中,我们通常需要组合使用上下文对象的多个功能:
@mcp.tool()
async def complex_operation(file_uris: List[str], ctx: Context):
"""演示如何组合使用Context的各种功能"""
try:
total_files = len(file_uris)
results = []
for i, file_uri in enumerate(file_uris, 1):
# 报告进度
await ctx.report_progress(i, total_files)
# 记录开始处理
await ctx.info(f"开始处理文件: {file_uri}")
try:
# 读取并分析文件
content_iter = await ctx.read_resource(file_uri)
content_list = list(content_iter)
# 记录分析结果
await ctx.debug(f"文件 {file_uri} 包含 {len(content_list)} 行内容")
results.append({
"file_uri": file_uri,
"status": "success",
"content_length": len(content_list)
})
except Exception as e:
await ctx.error(f"处理文件 {file_uri} 时出错: {str(e)}")
results.append({
"file_uri": file_uri,
"status": "error",
"error": str(e)
})
return {
"total_files": total_files,
"processed_files": len(results),
"results": results
}
except Exception as e:
await ctx.error(f"操作执行失败: {str(e)}")
raise
这个示例展示了如何在一个复杂操作中结合使用进度报告、日志记录和资源访问,以及如何处理可能出现的错误。
动态资源与上下文
MCP还支持动态资源,这些资源可以根据参数生成不同的内容:
@mcp.resource("users://{user_id}/profile")
def get_user_profile(user_id: str) -> str:
"""动态用户数据"""
return f"Profile data for user {user_id}"
上下文对象可以访问这些动态资源,使工具能够处理参数化的资源内容。
客户端接收上下文信息
在客户端,我们可以接收和处理工具发送的上下文信息:
# 测试日志记录
result = await session.call_tool("tool_with_logging")
# 测试进度报告
result = await session.call_tool("process_files", {
"files": ["file1.txt", "file2.txt", "file3.txt"]
})
# 测试资源访问
result = await session.call_tool("analyze_file", {
"file_uri": "users://123/profile"
})
# 测试组合使用
result = await session.call_tool("complex_operation", {
"file_uris": ["users://tomcat/profile"]
})
客户端可以根据接收到的日志、进度和错误信息,向用户提供适当的反馈。
上下文使用最佳实践
- 适当的日志级别:根据信息的重要性选择合适的日志级别
- 有意义的进度报告:在处理多个项目时提供准确的进度信息
- 错误处理:捕获并报告可能的错误,提供清晰的错误信息
- 资源验证:在访问资源之前验证资源URI的有效性
- 异步处理:使用异步方法处理长时间运行的任务,避免阻塞
- 用户友好的消息:提供对用户有帮助的、易于理解的消息
- 上下文状态管理:在复杂操作中维护上下文状态,确保一致性
上下文应用场景
上下文系统可以应用于多种场景:
- 数据处理:处理大量数据时报告进度和中间结果
- 文件操作:在处理多个文件时提供实时反馈
- API调用:在进行多个API调用时报告每个调用的状态
- 批量任务:执行批量任务时提供详细的执行日志
- 资源分析:分析资源内容并提供实时分析结果
- 错误诊断:在复杂操作中提供详细的错误诊断信息
结语
笔者暂未弄清楚context在实际开发的作用,如有人知道,记得告知笔者哦~~