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. 参数补全(Completions)
  • 2. 服务器:支持参数补全的 Prompt 与资源模板
  • 3. 客户端:请求并展示补全结果
  • 4. 运行与验证

1. 参数补全(Completions) #

本章主要介绍 MCP 的“参数补全(Completions)”机制,包括服务端如何为 Prompt 参数和资源模板参数提供智能补全建议,以及客户端如何请求补全并展示结果。你将学会:

  • 如何在服务端实现支持参数补全的 Prompt 和资源模板;
  • 如何编写补全处理器,动态返回参数候选项;
  • 客户端如何发起补全请求,并获取和展示补全结果。

2. 服务器:支持参数补全的 Prompt 与资源模板 #

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

# 导入 FastMCP 主类
from mcp.server.fastmcp import FastMCP

# 导入类型定义
from mcp.types import (
    Completion,  # 补全结果
    CompletionArgument,  # 补全参数
    CompletionContext,  # 补全上下文
    PromptReference,  # 提示参考
    ResourceTemplateReference,  # 资源模板参考
)

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


# 定义一个 Prompt,描述为“代码风格指导”,其参数支持补全
@mcp.prompt(description="代码风格指导")
def code_style_guide(language: str, style: str) -> str:
    # 根据编程语言和风格偏好生成代码指导
    return f"请为 {language} 语言提供 {style} 风格的代码指导。"


# 定义一个资源模板,格式为 github://{owner}/{repo},其参数支持补全
@mcp.resource("github://{owner}/{repo}")
def github_repo_info(owner: str, repo: str) -> str:
    # 获取 GitHub 仓库信息(示例资源)
    return f"GitHub 仓库 {owner}/{repo} 的信息:这是一个示例仓库。"


# 使用 @mcp.completion() 装饰器注册补全处理器
@mcp.completion()
async def handle_completion(
    ref: PromptReference | ResourceTemplateReference,  # 提示或资源模板参考
    argument: CompletionArgument,  # 补全参数
    context: CompletionContext | None,  # 补全上下文
) -> Completion | None:
    # 为 prompts 和 resources 提供补全建议

    # 如果是 Prompt 参数补全
    if isinstance(ref, PromptReference):
        # 针对 code_style_guide Prompt
        if ref.name == "code_style_guide":
            # 如果补全参数为 language
            if argument.name == "language":
                # 预设编程语言列表
                languages = ["Python", "JavaScript", "Java", "C++", "Go", "Rust"]
                # 根据输入值过滤匹配的语言
                filtered_languages = [
                    lang
                    for lang in languages
                    if lang.lower().startswith(argument.value.lower())
                ]
                # 返回补全结果
                return Completion(
                    values=filtered_languages,
                    hasMore=False,
                )
            # 如果补全参数为 style
            elif argument.name == "style":
                # 预设代码风格列表
                styles = [
                    "clean",
                    "functional",
                    "object-oriented",
                    "procedural",
                    "declarative",
                ]
                # 根据输入值过滤匹配的风格
                filtered_styles = [
                    style
                    for style in styles
                    if style.lower().startswith(argument.value.lower())
                ]
                # 返回补全结果
                return Completion(
                    values=filtered_styles,
                    hasMore=False,
                )

    # 如果是资源模板参数补全
    if isinstance(ref, ResourceTemplateReference):
        # 针对 github://{owner}/{repo} 资源模板
        if ref.uri == "github://{owner}/{repo}":
            # 如果补全参数为 owner
            if argument.name == "owner":
                # 预设 GitHub 用户名列表
                owners = [
                    "microsoft",
                    "google",
                    "facebook",
                    "netflix",
                    "modelcontextprotocol",
                ]
                # 根据输入值过滤匹配的用户名
                filtered_owners = [
                    owner
                    for owner in owners
                    if owner.lower().startswith(argument.value.lower())
                ]
                # 返回补全结果
                return Completion(
                    values=filtered_owners,
                    hasMore=False,
                )
            # 如果补全参数为 repo
            elif argument.name == "repo":
                # 仓库名补全,需考虑 owner 上下文
                if context and context.arguments and context.arguments.get("owner"):
                    owner = context.arguments.get("owner")
                    # 针对不同 owner 提供不同仓库名列表
                    if owner == "microsoft":
                        repos = ["vscode", "typescript", "dotnet", "azure-sdk"]
                    elif owner == "google":
                        repos = ["tensorflow", "kubernetes", "go", "chromium"]
                    elif owner == "modelcontextprotocol":
                        repos = ["python-sdk", "servers", "specification", "website"]
                    else:
                        repos = ["main", "master", "develop", "feature"]

                    # 根据输入值过滤匹配的仓库名
                    filtered_repos = [
                        repo
                        for repo in repos
                        if repo.lower().startswith(argument.value.lower())
                    ]
                    # 返回补全结果
                    return Completion(
                        values=filtered_repos,
                        hasMore=False,
                    )

    # 如果没有匹配的补全规则,返回 None
    return None


# 主入口:以 stdio 方式运行服务器
if __name__ == "__main__":
    mcp.run(transport="stdio")

说明:

  • 补全回调函数接收参数名、当前值、上下文参数,返回建议列表。
  • 上下文参数可用于提供相关补全(如根据 owner 补全 repo)。
  • 实际实现中,你可能需要扩展 FastMCP 或使用低层 Server 来完全支持补全。

3. 客户端:请求并展示补全结果 #

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

# 连接到 completions_server.py,演示如何请求参数补全

# 导入 asyncio,用于运行异步逻辑
import asyncio

# 导入 os,用于计算服务器脚本路径
import os

# 从 mcp 包导入 ClientSession、StdioServerParameters 和 types,用于会话、stdio 参数与类型定义
from mcp import ClientSession, StdioServerParameters, types

# 从 mcp.client.stdio 导入 stdio_client,作为 stdio 客户端工厂
from mcp.client.stdio import stdio_client


# 定义主异步函数
async def main() -> None:
    # 计算当前文件的绝对路径所在目录
    base_dir = os.path.dirname(os.path.abspath(__file__))
    # 拼接得到 completions_server.py 的绝对路径
    server_path = os.path.join(base_dir, "completions_server.py")

    # 配置以 stdio 方式启动服务器
    server_params = StdioServerParameters(
        command="python",  # 使用 python 命令启动
        args=[server_path],  # 启动参数为服务器脚本路径
        env={},  # 环境变量为空
    )

    # 建立 stdio 连接并创建客户端会话
    async with stdio_client(server_params) as (read, write):
        # 使用 read 和 write 创建 ClientSession
        async with ClientSession(read, write) as session:
            # 初始化会话
            await session.initialize()

            # 列出所有 Prompt
            prompts = await session.list_prompts()
            # 打印所有 Prompt 的名称
            print("[Prompts]", [p.name for p in prompts.prompts])

            # 列出所有资源模板
            templates = await session.list_resource_templates()
            # 打印所有资源模板的 uriTemplate
            print(
                "[ResourceTemplates]",
                [t.uriTemplate for t in templates.resourceTemplates],
            )

            # 如果存在 Prompt,则进行参数补全演示
            if prompts.prompts:
                # 取第一个 Prompt 的名称
                prompt_name = prompts.prompts[0].name
                # 打印 Prompt 补全示例标题
                print(f"\n=== Prompt 补全示例:{prompt_name} ===")
                # 打印当前 Prompt 名称
                print(f"prompt_name: {prompt_name}")
                # 请求 language 参数的补全,已输入 "py"
                language_completion = await session.complete(
                    ref=types.PromptReference(type="ref/prompt", name=prompt_name),
                    argument={"name": "language", "value": "py"},
                )
                # 打印 language 参数的补全结果
                print(f"language_completion: {language_completion}")
                # 打印 language='py' 的补全建议
                print(
                    f"language='py' 的补全建议:{language_completion.completion.values}"
                )

                # 请求 style 参数的补全,已输入 "func"
                style_completion = await session.complete(
                    ref=types.PromptReference(type="ref/prompt", name=prompt_name),
                    argument={"name": "style", "value": "func"},
                )
                # 打印 style='func' 的补全建议
                print(f"style='func' 的补全建议:{style_completion.completion.values}")

            # 如果存在资源模板,则进行资源模板参数补全演示
            if templates.resourceTemplates:
                # 取第一个资源模板
                template = templates.resourceTemplates[0]
                # 打印资源模板补全示例标题
                print(f"\n=== 资源模板补全示例:{template.uriTemplate} ===")

                # 请求 owner 参数的补全,已输入 "mod"
                owner_completion = await session.complete(
                    ref=types.ResourceTemplateReference(
                        type="ref/resource", uri=template.uriTemplate
                    ),
                    argument={"name": "owner", "value": "mod"},
                )
                # 打印 owner='mod' 的补全建议
                print(f"owner='mod' 的补全建议:{owner_completion.completion.values}")

                # 请求 repo 参数的补全,已输入 "py",并提供 owner 上下文
                repo_completion = await session.complete(
                    ref=types.ResourceTemplateReference(
                        type="ref/resource", uri=template.uriTemplate
                    ),
                    argument={"name": "repo", "value": "py"},
                    context_arguments={"owner": "modelcontextprotocol"},
                )
                # 打印 repo='py' 的补全建议(owner=modelcontextprotocol)
                print(
                    f"repo='py' 的补全建议(owner=modelcontextprotocol):{repo_completion.completion.values}"
                )


# 判断是否为主程序入口
if __name__ == "__main__":
    # 运行主异步函数
    asyncio.run(main())

说明:

  • session.complete() 用于请求参数补全。
  • PromptReference 引用 Prompt,ResourceTemplateReference 引用资源模板。
  • context_arguments 提供上下文信息,影响补全结果。

4. 运行与验证 #

cd C:\mcp-project
call .venv\Scripts\activate
python test_client_completions.py

预期输出:

[Prompts] ['code_style_guide']
[ResourceTemplates] ['github://{owner}/{repo}']

=== Prompt 补全示例:code_style_guide ===
prompt_name: code_style_guide
language_completion: meta=None completion=Completion(values=['Python'], total=None, hasMore=False)
language='py' 的补全建议:['Python']
style='func' 的补全建议:['functional']

=== 资源模板补全示例:github://{owner}/{repo} ===
owner='mod' 的补全建议:['modelcontextprotocol']
repo='py' 的补全建议(owner=modelcontextprotocol):['python-sdk']

访问验证

请输入访问令牌

Token不正确,请重新输入