跳到主内容

MCP Completions 实战:给 Prompt 参数加上自动补全

100%
MCP Completions 实战:给 Prompt 参数加上自动补全

结论先说:MCP 的 Completions 是一套「服务端给候选值」的能力,它只覆盖 prompt 参数和 resource 模板变量,不覆盖工具入参。用对了能把用户的自由文本输入变成下拉选择,用错了(想拿它补全工具参数)会白忙一场。这是 MCP 里最容易被忽略、也最容易被误解的一个可选能力。

一句话定位:Completions = 服务端自动补全。客户端把用户已输入的前缀发给你,你回一组候选字符串。

Completions 到底补全什么

按 MCP 规范,Completions 让服务器为「 prompt 的参数」和「 resource 模板的变量」提供补全建议。用户在填这两个东西的时候,客户端弹一个下拉,候选值由你的服务端实时给出。

它的引用类型只有两种:

类型引用对象示例
ref/prompt按名字引用一个 prompt{"type":"ref/prompt","name":"code_review"}
ref/resource按 URI 引用资源模板{"type":"ref/resource","uri":"file:///{path}"}

注意这里没有 ref/tool。很多人以为 Completions 能补全工具入参,规范里并没有这一项——工具参数的约束要靠 JSON Schema 的 enum 、描述和校验来做。

协议长什么样

请求用的是 completion/complete 方法,参数结构非常小:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "completion/complete",
  "params": {
    "ref": { "type": "ref/prompt", "name": "code_review" },
    "argument": { "name": "language", "value": "py" }
  }
}

服务端回一组建议值,并可选带上总数和「还有更多」标记:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "completion": {
      "values": ["python", "pytorch", "pyside"],
      "total": 10,
      "hasMore": true
    }
  }
}

三个返回字段的约束要记牢:values 单次最多 100 条;total 可以大于实际返回的条数;hasMore 表示还有没返回的候选,即使总数未知也能置 true 。

多参数联动:靠 context 传递已填值

当 prompt 有多个参数时,后一个参数的候选项往往依赖前一个。规范为此提供了 context.arguments,把用户已经填好的值一并带过来:

{
  "ref": { "type": "ref/prompt", "name": "code_review" },
  "argument": { "name": "framework", "value": "fla" },
  "context": { "arguments": { "language": "python" } }
}

服务端据此就能只返回 python 生态下的框架名。但规范也明确说了:客户端不保证一定会带 context。所以服务端的处理原则是——context 缺失时返回空列表,绝不抛异常。

怎么声明这个能力

服务端必须在能力声明里带上 completions:

{
  "capabilities": {
    "completions": {}
  }
}

不同 SDK 的封装程度不一样,这是选型时值得留意的一点:

  • Python SDK:注册一个 @mcp.completion() 处理函数即可,SDK 看到处理函数就自动声明 completions 能力,无需手动写。函数接收 ref、argument、context 三个参数,返回 Completion(values=[...]);没有建议时返回 None,SDK 会转成空数组。
  • TypeScript SDK:用 completable() 包裹 argsSchema 里的某个字段,第一个被包裹的字段会顺带注册处理函数并声明能力。资源模板则通过 complete 映射,按变量各挂一个回调。

Python 侧的最小实现大概是这样:

from mcp.server import MCPServer
from mcp.types import Completion, CompletionArgument, CompletionContext, PromptReference, ResourceTemplateReference

mcp = MCPServer("GitHub Explorer")
LANGUAGES = ["go", "javascript", "python", "rust", "typescript"]

@mcp.prompt()
def review_code(language: str, code: str) -> str:
    """Review a snippet of code."""
    return f"Review this {language} code:\n{code}"

@mcp.completion()
async def handle_completion(ref, argument, context):
    if isinstance(ref, PromptReference) and argument.name == "language":
        return Completion(values=[l for l in LANGUAGES if l.startswith(argument.value)])
    return None

有个细节很容易踩:SDK 不会替你过滤。argument.value 只是用户已输入的前缀,返回什么就显示什么,前缀匹配要你自己写。

错误处理与限流

规范对 Completions 的错误码给了明确约定,照着实现即可:

场景错误码
不支持该能力-32601 Method not found
prompt 名字非法 / 缺少必填参数-32602 Invalid params
服务端内部错误-32603 Internal error
规范对安全的要求是「必须」级别:校验所有补全输入、做限流、控制敏感建议的可见性,并防止通过补全过程泄露信息。补全接口是个高频、低门槛的入口,很容易被当成枚举接口来打。

服务端与客户端各自该做什么

规范把两边的最佳实践分得很清楚,落地时对着清单自查就行:

  • 服务端:按相关度排序返回;合适时做模糊匹配;对补全请求限流;校验所有输入。
  • 客户端:对高频输入做防抖;缓存补全结果;优雅处理缺失或部分结果。

这和我们在 MCP 工具注解(annotations) 里讲的思路一致——协议把「怎么描述」和「怎么使用」分开约定,服务端负责给足信息,客户端负责用得克制。


  1. 确认补全对象:只有 prompt 参数和 resource 模板变量能补全。如果要约束的是工具入参,改 JSON Schema,别用 Completions 。

  2. 写处理函数:按 SDK 方式注册(Python 用装饰器,TS 用 completable),分支处理 ref 类型和 argument.name 。

  3. 处理 context 缺失:context 为空时返回空列表,不要抛错,客户端可能根本不发。

  4. 加限流与截断:单次结果截断到 100 条,对请求做频率限制,避免补全接口被滥用为枚举通道。

用 TypeScript 让一个字段的候选项依赖另一个字段
async function completeBranch(value: string, context?: { arguments?: Record<string, string> }) {
  const repo = context?.arguments?.repo;
  if (!repo) return [];
  return (branchesByRepo[repo] ?? []).filter(b => b.startsWith(value));
}

repo 已填为 typescript-sdk、 branch 输入 rel 时,返回该仓库下的 release 分支。 context 缺失时直接返回空数组。

和 prompts / resources 的关系

Completions 是依附于 prompts 和 resources 的增强能力,本身不独立存在。如果你还没理清这两个原语,建议先看 MCP 的 resources 与 prompts 指南,再回来做补全。服务端与客户端的整体开发流程可以参照 Python 开发 MCP 客户端 与 TypeScript 构建 MCP Server。还没入门的话,MCP 入门教程 是起点。

先搞懂 prompts 与 resources

Completions 能补全工具的入参吗?
不能。规范只定义了 ref/prompt 和 ref/resource 两种引用类型。工具入参的约束请用 JSON Schema 的 enum 、格式校验和清晰描述来表达。

需要手动声明 completions 能力吗?
取决于 SDK 。 Python SDK 注册处理函数即自动声明;按规范实现时,服务端必须在 capabilities 里带上 completions,否则客户端不会发请求。

一次最多能返回多少条候选?
values 数组上限 100 条。可以用 total 告知实际候选总数,用 hasMore 标记还有更多,让客户端决定要不要继续。

context 一定会有吗?
不一定。规范说明客户端不保证发送 context,所以服务端遇到缺失时应返回空列表,绝不抛异常。

小结

Completions 是个小而完整的能力:请求三个字段、响应三个字段,却能把「让用户猜该填什么」变成「让用户选」。记住它的边界(只管 prompt 和 resource)、写好 context 缺失的兜底、补上限流,这个能力就很稳。

资料来源:Model Context Protocol Specification:Completion、MCP Python SDK:Completions、MCP TypeScript SDK:Completion。

这篇有帮助吗?
云上的幻象
云上的幻象查看主页

七彩云博客,分享 WordPress 建站实战与 AI 工具测评,覆盖服务器运维、站长工具、软件资源与电商运营干货,专注原创实用的主题插件、网站加速与安全优化教程。

952文章4评论

相关文章

评论 (0)

欢迎你,新朋友,感谢参与互动!文明发言,理性交流 · 首次评论将在审核后展示