ai
  • index
  • 1.首页
  • 2.介绍
  • 3.架构概览
  • 4.服务器概念
  • 5.客户端概念
  • 6.版本控制
  • 7.连接到远程MCP服务器
  • 8.连接到本地MCP服务器
  • json_rpc
  • 9.构建一个MCP服务器
  • 10.检查员
  • 11.构建一个MCP客户端
  • 14.架构
  • 15.基础协议概述
  • 16.生命周期
  • 17.传输
  • 18.授权
  • 19.安全最佳实践
  • 20.取消
  • 21.Ping
  • 22.进展
  • 23.Roots
  • 24.采样
  • 25.启发
  • 26.服务器特性
  • 27.提示词
  • 28.资源
  • 29.工具
  • 30.完成
  • 31.日志记录
  • 32.分页
  • 33.架构参考
  • URI模板
  • 12.实现
  • http.server
  • 动态客户端注册协议
  • 受保护资源元数据
  • 授权服务器元数据
  • JWKS
  • PKCE
  • PyJWT
  • secrets
  • watchfiles
  • 实现authorization
  • 实现cancel
  • 实现completion
  • 实现logging
  • 实现pagination
  • 实现process
  • 实现transport
  • psutil
  • pytz
  • zoneinfo
  • contextlib
  • Starlette
  • mcp.1.starter
  • mcp.2.Resource
  • mcp.3.structured_output
  • mcp.4.prompts
  • mcp.5.context
  • mcp.6.streamable
  • mcp.7.lowlevel
  • mcp.8.Completion
  • mcp.9.Elicitation
  • mcp.10.oauth
  • mcp.11.integration
  • mcp.12.best
  • mysql-mcp
  • databases
  • uvicorn
  • asynccontextmanager
  • AsyncExitStack
  • streamable
  • aiohttp
  • publish
  • email
  • schedule
  • twine
  • 1.教学文档总览
  • 2.教师使用指南
  • 3.教学系统快速参考
  • 4.新生入门指南
  • 5.学生使用指南
  • 1. 引导提问(Elicitation)
  • 2. 服务器:在工具执行中发起引导提问
  • 3. 运行与验证

1. 引导提问(Elicitation) #

本章主要介绍如何使用 MCP 的引导提问机制,包括在工具执行中向用户发起结构化信息收集,以及客户端如何处理引导提问并返回用户响应。你将学会:

  • 理解 Elicitation 机制:在工具执行中向用户发起结构化信息收集
  • 在服务端使用 ctx.elicit() 发起引导提问,定义提问的 Schema
  • 在客户端侧处理 Elicitation 请求并返回用户响应

2. 服务器:在工具执行中发起引导提问 #

新建 C:\mcp-project\elicitation_server.py:

# 导入异步编程相关模块
import asyncio

# 导入 Pydantic,用于数据模型和校验
from pydantic import BaseModel, Field, field_validator

# 导入 MCP 服务器主类和上下文类型
from mcp.server.fastmcp import FastMCP, Context
from mcp.server.session import ServerSession

# 创建 FastMCP 服务器实例,命名为 "Elicitation  Server"
mcp = FastMCP(name="Elicitation  Server")


# 定义任务信息的数据结构
class TaskInfo(BaseModel):
    """任务信息数据结构"""

    # 任务标题,字符串类型
    title: str = Field(description="任务标题")
    # 任务优先级,字符串类型,限定 low/medium/high
    priority: str = Field(description="任务优先级 (low/medium/high)")

    # 校验器:确保 priority 字段值合法
    @field_validator("priority")
    def validate_priority(cls, v):
        # 如果优先级不在允许的范围内,抛出异常
        if v.lower() not in ["low", "medium", "high"]:
            raise ValueError("优先级必须是 low、medium 或 high")
        # 返回小写形式
        return v.lower()


# 定义用户偏好设置的数据结构
class UserPreferences(BaseModel):
    """用户偏好设置数据结构"""

    # 是否检查替代选项,布尔类型
    checkAlternative: bool = Field(description="是否检查替代选项?")
    # 替代选项名称,字符串类型,默认值为 "option_b"
    alternativeOption: str = Field(default="option_b", description="替代选项名称")


# 定义确认操作的数据结构
class ConfirmationData(BaseModel):
    """确认操作数据结构"""

    # 是否继续执行,布尔类型
    proceed: bool = Field(description="是否继续执行?")
    # 继续或取消的原因,字符串类型,默认为空
    reason: str = Field(default="", description="继续或取消的原因(可选)")


# 工具1:创建任务(使用 elicitation 收集任务信息)
@mcp.tool()
async def create_task(ctx: Context[ServerSession, None]) -> str:
    """创建任务,使用 elicitation 收集任务信息"""
    try:
        # 发起用户引导,收集任务信息
        result = await ctx.elicit(message="请提供任务信息:", schema=TaskInfo)

        # 如果用户接受并填写了数据
        if result.action == "accept" and result.data:
            task_info = result.data
            # 返回任务创建成功信息
            return f" 任务创建成功:{task_info.title} (优先级: {task_info.priority})"
        # 如果用户拒绝
        elif result.action == "decline":
            return " 用户拒绝了任务创建请求"
        # 其他情况(如取消)
        else:
            return " 任务创建被取消"

    # 捕获异常并返回错误信息
    except Exception as e:
        return f" 任务创建失败:{str(e)}"


# 工具2:收集用户偏好
@mcp.tool()
async def collect_preferences(ctx: Context[ServerSession, None]) -> str:
    """收集用户偏好设置"""
    try:
        # 发起用户引导,收集偏好设置
        result = await ctx.elicit(
            message="请告诉我你的偏好设置:", schema=UserPreferences
        )

        # 如果用户接受并填写了数据
        if result.action == "accept" and result.data:
            prefs = result.data
            # 返回收集到的偏好设置
            return f" 偏好设置已收集:检查替代={prefs.checkAlternative}, 替代选项={prefs.alternativeOption}"
        # 如果用户拒绝
        elif result.action == "decline":
            return " 用户拒绝了偏好设置收集"
        # 其他情况(如取消)
        else:
            return " 偏好设置收集被取消"

    # 捕获异常并返回错误信息
    except Exception as e:
        return f" 偏好设置收集失败:{str(e)}"


# 工具3:确认操作
@mcp.tool()
async def confirm_action(ctx: Context[ServerSession, None]) -> str:
    """确认重要操作"""
    try:
        # 发起用户引导,收集确认信息
        result = await ctx.elicit(
            message="这是一个重要操作,请确认是否继续:", schema=ConfirmationData
        )

        # 如果用户接受并填写了数据
        if result.action == "accept" and result.data:
            confirm_data = result.data
            # 如果用户选择继续
            if confirm_data.proceed:
                reason = confirm_data.reason or "未提供原因"
                return f" 操作已确认,继续执行。原因:{reason}"
            # 如果用户选择不继续
            else:
                reason = confirm_data.reason or "未提供原因"
                return f" 操作被拒绝。原因:{reason}"
        # 如果用户拒绝
        elif result.action == "decline":
            return " 用户拒绝了确认请求"
        # 其他情况(如取消)
        else:
            return " 确认请求被取消"

    # 捕获异常并返回错误信息
    except Exception as e:
        return f" 确认操作失败:{str(e)}"


# 主函数:启动服务器
async def main():
    """启动 MCP 服务器"""
    # 打印服务器启动信息
    print(" 启动 Elicitation  Server...")
    print(" 可用工具:")
    print("  - create_task: 创建任务")
    print("  - collect_preferences: 收集用户偏好")
    print("  - confirm_action: 确认操作")

    # 启动服务器,使用 stdio 传输方式
    mcp.run(transport="stdio")


# 程序入口
if __name__ == "__main__":
    try:
        # 运行主函数,启动事件循环
        asyncio.run(main())
    except KeyboardInterrupt:
        # 捕获 Ctrl+C,优雅退出
        print("\n 服务器已停止")
    except Exception as e:
        # 捕获其他异常,打印错误信息和建议
        print(f" 服务器启动失败:{e}")
        print(" 建议:检查 MCP 版本是否支持 elicitation 功能")

要点:

  • 使用 ctx.elicit() 发起引导提问
  • 定义引导提问的数据结构(Pydantic Schema)
  • 处理 ElicitationResult 的不同响应状态

3. 运行与验证 #

mcp dev elicitation_server.py

访问验证

请输入访问令牌

Token不正确,请重新输入