MCP高级特性:上下文对象与交互式工具开发

8 阅读5分钟

在构建复杂的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"]
})

客户端可以根据接收到的日志、进度和错误信息,向用户提供适当的反馈。

上下文使用最佳实践

  1. 适当的日志级别:根据信息的重要性选择合适的日志级别
  2. 有意义的进度报告:在处理多个项目时提供准确的进度信息
  3. 错误处理:捕获并报告可能的错误,提供清晰的错误信息
  4. 资源验证:在访问资源之前验证资源URI的有效性
  5. 异步处理:使用异步方法处理长时间运行的任务,避免阻塞
  6. 用户友好的消息:提供对用户有帮助的、易于理解的消息
  7. 上下文状态管理:在复杂操作中维护上下文状态,确保一致性

上下文应用场景

上下文系统可以应用于多种场景:

  1. 数据处理:处理大量数据时报告进度和中间结果
  2. 文件操作:在处理多个文件时提供实时反馈
  3. API调用:在进行多个API调用时报告每个调用的状态
  4. 批量任务:执行批量任务时提供详细的执行日志
  5. 资源分析:分析资源内容并提供实时分析结果
  6. 错误诊断:在复杂操作中提供详细的错误诊断信息

结语

笔者暂未弄清楚context在实际开发的作用,如有人知道,记得告知笔者哦~~