Go 语言实现 MCP 服务中的 Prompt:从核心类型到服务端实践

Owen
Owen
发布时间:2026-08-25| 91人浏览过
原创

前言

MCP 正在把 AI 与外部系统的连接方式逐步标准化,而 Prompt 也从“写提示词”变成了服务端可以注册、发现和动态生成的能力。本文结合 Go 官方 SDK,把 Prompt 的核心类型、代码审查模板实现、多消息返回和运行时更新拆开讲清楚,方便你判断它在项目里该怎么设计、该把边界放在哪里。

在 MCP 逐渐成为 AI 应用与外部系统之间通用接口的背景下,Prompt 不再只是“写一段提示词”这么简单,而是服务端可以注册、客户端可以发现、还能按参数动态生成内容的能力。下面结合 Go 官方 SDK 的类型设计与示例代码,拆开讲清楚 Prompt 到底解决什么问题、该怎么实现,以及在动态更新和安全控制上应该注意哪些边界。

MCP 里的 Prompt,到底和普通提示词有什么区别

在 Anthropic 推出的 MCP(Model Context Protocol)里,常见的三个核心概念分别是:

  • Prompt:定义可复用的提示模板。
  • Tool:扩展 AI 的执行能力。
  • Resource:提供数据访问接口。

其中,Prompt 更适合处理“把某一类任务封装成统一模板”这件事。它的作用不是单纯存一段文案,而是让服务端把提示结构标准化,客户端再通过参数填充,生成实际要发给模型的消息内容。

从使用价值看,MCP Prompt 主要有四个特点:

  • 标准化:模板定义格式统一,便于不同客户端接入。
  • 可复用:同一份模板可以多次调用,减少重复编写。
  • 参数化:支持动态参数,能适配不同任务输入。
  • 可发现:客户端可以直接发现服务器已经提供的 Prompt。

这里还需要分清一个常见误区:MCP Prompt 并不等于系统 Prompt。

  • 系统 Prompt 更像对模型身份和行为的持续约束,例如“你是一个专业的代码审查专家”,它会贯穿整个对话过程。
  • MCP Prompt 则是服务端定义的任务模板机制,用来按需生成具体提示内容,支持参数化、支持动态返回消息,也可以在内部包含系统 Prompt 风格的内容。

简单说,系统 Prompt 更接近“AI 是谁”,而 MCP Prompt 更接近“这次要它完成什么任务,以及任务模板长什么样”。

用 Go SDK 实现 Prompt,先看清三个核心类型

如果使用官方 Go SDK github.com/modelcontextprotocol/go-sdk/mcp,实现 Prompt 时最先要理解的是 Prompt 定义、参数定义和处理函数三部分。

MCP Prompt 在 Go SDK 中的基本结构示意,包含 Prompt、参数定义与处理函数之间的关系。
Prompt 的三层结构先把 Prompt 的声明、参数和处理函数关系看清,后面的服务端实现就不容易混淆。

1. Prompt 结构体:描述模板本身

Prompt 负责定义一个模板的元信息:

代码审查 Prompt 的请求到返回流程示意,突出参数填充、默认值与消息生成。
代码审查 Prompt 的生成路径代码审查模板的重点不在文案本身,而在参数如何进入 Handler,并被整理成可直接返回的消息。
type Prompt struct {
    Name        string            // 唯一标识符
    Title       string            // 显示标题
    Description string            // 功能描述
    Arguments   []*PromptArgument // 参数列表
}

这里面最关键的是 Name。它是模板的唯一标识,客户端后续调用时依赖的也是这个名字。Title 和 Description 则更偏向展示和说明,帮助客户端或模型理解这个模板是干什么的。Arguments 定义了模板允许接收哪些参数。

2. PromptArgument:把模板做成可配置接口

模板是否能真正复用,取决于参数设计是否合理。SDK 中对应的结构是:

MCP Prompt 运行时动态更新与客户端通知的示意图,表现增删模板与列表变更通知。
Prompt 列表的动态变化当 Prompt 不再固定写死在启动阶段,MCP 的动态更新能力才会真正体现出服务端管理价值。
type PromptArgument struct {
    Name        string // 参数名称
    Description string // 参数描述
    Required    bool   // 是否必填
}

一个 Prompt 可以有多个参数。通过把任务中的可变部分抽成参数,就能把一类操作做成稳定模板,例如代码审查里的“代码内容”“编程语言”,技术问答里的“问题”“领域”等。

3. PromptHandler:真正决定返回什么消息

当客户端请求某个 Prompt 的具体内容时,会进入处理函数:

type PromptHandler func(context.Context, *GetPromptRequest) (*GetPromptResult, error)

也就是说,Prompt 只负责声明“我是什么模板、接受哪些参数”,而 PromptHandler 才负责根据请求参数,生成最终返回给客户端的消息内容。实际项目里,很多逻辑都会放在这里,比如参数兜底、权限判断、上下文拼装,甚至根据用户身份切换不同模板结果。

实战示例:做一个代码审查 Prompt

理解完基础类型后,可以直接看一个更接近实际使用场景的例子。这里的目标是实现一个代码审查模板:客户端传入代码内容,服务端返回一段结构化的代码审查提示。

先创建基础 MCP Server

服务端初始化方式比较直接:

server := mcp.NewServer(&mcp.Implementation{
    Name:    "prompt-demo", Version: "1.0.0",
}, nil)

// 添加Prompt...

if err := server.Run(ctx, &mcp.StdioTransport{}); err != nil {
    log.Fatal(err)
}

这里注册了一个名为 prompt-demo、版本为 1.0.0 的 MCP 服务,并通过 mcp.StdioTransport{} 运行。对示例工程来说,这已经足够承载 Prompt 注册与调用。

注册 Prompt 模板

接着通过 AddPrompt 注册模板定义和处理函数:

server.AddPrompt(&mcp.Prompt{
    Name: "code_review", Title: "代码审查助手",
    Description: "对代码进行专业的质量审查",
    Arguments: []*mcp.PromptArgument{
        {Name: "code", Description: "需要审查的代码", Required: true},
        {Name: "language", Description: "编程语言", Required: false},
    },
}, handleCodeReview)

这个模板的设计比较典型:

  • code 是核心输入,因此设为必填。
  • language 只是增强上下文,不一定每次都提供,所以设为可选。
  • Description 明确写出用途,有利于客户端展示,也有助于调用方理解这个模板的使用场景。

在 Handler 中根据参数生成消息

真正的内容拼装发生在处理函数里:

func handleCodeReview(ctx context.Context, req *mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
    code := areq.Params.Argumentsrgs["code"]
    language := arreq.Params.Argumentsgs["language"]
    if language == "" { language = "未知" }

    promptText := fmt.Sprintf("请对以下%s代码进行审查:n%s", language, code)
    return &mcp.GetPromptResult{
        Messages: []*mcp.PromptMessage{{
            Role: mcp.RoleUser,
            Content: &mcp.TextContent{Text: promptText},
        }},
    }, nil
}

这段代码传达出的实现思路很清楚:

  • 先从请求参数中取出 code 和 language。
  • 如果调用方没传 language,就在服务端补一个默认值。
  • 再把这些参数拼成一条用户消息,放进 GetPromptResult 的 Messages 里返回。

换句话说,Prompt 并不是只返回一段字符串,而是返回一组可直接参与对话的消息结构。这样做的好处是,模板可以继续扩展成更复杂的消息序列,而不是被限制在单一文本输出里。

不止单条消息:多消息 Prompt 和动态更新怎么做

如果你的场景需要预设对话上下文,Prompt 还可以返回多条消息。它并不局限于“给模型发一句话”,而是能把一个完整的对话起手式封装起来。

多消息 Prompt 适合哪些场景

常见情况包括技术问答、角色预设、流程化分析等。示例里给出了一个技术问答 Prompt:

server.AddPrompt(&mcp.Prompt{
    Name: "tech_qa", Title: "技术问答助手",
    Arguments: []*mcp.PromptArgument{
        {Name: "question", Required: true},
        {Name: "domain", Required: false},
    },
}, handleTechQA)

func handleTechQA(ctx context.Context, req *mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
    args := req.Params.Arguments
    return &mcp.GetPromptResult{
        Messages: []*mcp.PromptMessage{
            {Role: mcp.RoleUser, Content: &mcp.TextContent{Text: args["question"]}},
        },
    }, nil
}

虽然示例中只放了一条消息,但这里的返回类型已经说明了扩展空间:你完全可以继续加入更多消息,用来预设上下文、限制回答范围,或者构造多轮对话起点。

Prompt 列表可以在运行时调整

MCP 的另一个实用点是,Prompt 不必在服务启动时一次性定死。运行中的服务也可以动态增删模板。

移除某个 Prompt:

// 移除指定的Prompt
server.RemovePrompts("old_prompt_name")

运行时添加新 Prompt:

server.AddPrompt(&mcp.Prompt{Name: "advanced_analysis"}, handler)

一旦 Prompt 列表发生变化,SDK 会自动向已连接客户端发送 notifications/prompts/list_changed 通知。对客户端来说,这意味着它可以感知服务端模板集合已经变化,并重新同步可用 Prompt 列表。

这类能力很适合做按租户开放功能、按权限暴露模板,或者根据业务状态临时启用某类分析 Prompt 的场景。

落地时更重要的,是参数设计和安全边界

示例代码能帮助理解接口,但真正上线时,Prompt 是否好用、是否可维护,往往取决于一些更基础的设计细节。

参数设计要尽量克制

  • 必填参数最小化:只保留真正不可缺少的输入,减少调用门槛。
  • 为可选参数设置默认值:把兜底逻辑放在 Handler 里,比要求调用方每次都传完整参数更稳妥。
  • 参数说明写清楚:不仅是给人看,也是给接入方和模型理解模板用途。

一个常见问题是,把模板设计成“看起来很强大”,结果参数多到调用方难以下手。与其做一个参数繁杂的大模板,不如把任务边界收紧,保持 Prompt 的职责清晰。

安全问题不能留到后面补

  • 输入验证:所有参数都要做校验,尤其是文本拼接场景,需要防止注入式输入破坏提示结构。
  • 敏感信息过滤:不要把秘钥、内部路径、用户隐私等内容直接拼进 Prompt。
  • 权限控制:不同用户看到的 Prompt 列表未必相同,必要时应按身份动态暴露。

因为 Prompt 本质上会进入模型上下文,所以它不仅是一个“模板接口”,也是一层输入面。凡是会进入模型的内容,都值得用服务端思维去处理,而不只是按字符串拼接来看待。

从模板能力出发,才能真正用好 MCP Prompt

用 Go 官方 MCP SDK 实现 Prompt,本质上并不复杂:先声明模板元信息,再定义参数,最后在 Handler 中根据请求动态返回消息。难点不在 API 本身,而在于你是否把 Prompt 当成可管理、可发现、可演进的服务能力来设计。

从单条消息的代码审查模板,到支持上下文预设的技术问答,再到运行时动态增删 Prompt,MCP 给出的并不是“提示词写法”,而是一套面向服务端的组织方式。对正在构建 AI 应用的人来说,掌握这套机制,意味着你可以把提示能力沉淀成稳定接口,而不是散落在各处的临时字符串。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。