核心概念
了解 MCP 的基本概念以及 MCP-Go 如何实现这些概念,对于构建高效的 MCP 服务端和客户端至关重要。
MCP 协议基础
Model Context Protocol 定义了四个核心概念,使 LLM 能够安全有效地与外部系统交互。
资源
资源类似于 GET 端点 - 以只读方式向 LLM 暴露数据。可以将其视为 LLM 可以访问的文件、数据库记录或 API 响应。
关键特性:
- 只读:LLM 可以获取但不能修改资源
- 基于 URI:每个资源都有唯一的标识符
- 类型化内容:资源指定其 MIME 类型(文本、JSON、二进制等)
- 动态或静态:可以是预定义的或按需生成的
示例用例:
- 文件系统访问(
file:///path/to/document.txt) - 数据库记录(
db://users/123) - API 数据(
api://weather/current) - 配置文件(
config://app.json)
go
// 静态资源
resource := mcp.NewResource(
"docs://readme",
"Project README",
mcp.WithResourceDescription("The project's main documentation"),
mcp.WithMIMEType("text/markdown"),
)
// 带模板的动态资源
userResource := mcp.NewResource(
"users://{user_id}",
"User Profile",
mcp.WithResourceDescription("User profile information"),
mcp.WithMIMEType("application/json"),
)工具
工具类似于 POST 端点 - 提供 LLM 可以调用以执行操作或计算的功能。
关键特性:
- 面向操作:工具执行操作而不仅仅是返回数据
- 参数化:接受结构化输入参数
- 类型化模式:定义期望的参数类型和约束
- 返回结果:向 LLM 提供结构化输出
示例用例:
- 计算(
calculate、convert_units) - 文件操作(
create_file、search_files) - API 调用(
send_email、create_ticket) - 系统命令(
run_command、check_status)
go
// 简单计算工具
calcTool := mcp.NewTool("calculate",
mcp.WithDescription("Perform arithmetic operations"),
mcp.WithString("operation",
mcp.Required(),
mcp.Enum("add", "subtract", "multiply", "divide"),
),
mcp.WithNumber("x", mcp.Required()),
mcp.WithNumber("y", mcp.Required()),
)
// 文件创建工具
fileTool := mcp.NewTool("create_file",
mcp.WithDescription("Create a new file with content"),
mcp.WithString("path", mcp.Required()),
mcp.WithString("content", mcp.Required()),
mcp.WithString("encoding", mcp.Default("utf-8")),
)提示词
提示词是可重用的交互模板,用于帮助构建用户与 LLM 之间的对话结构。
关键特性:
- 基于模板:使用占位符获取动态内容
- 可重用:可以使用不同参数多次调用
- 结构化:定义清晰的输入参数和期望输出
- 上下文感知:可以包含相关资源或工具建议
示例用例:
- 代码审查模板
- 文档生成
- 数据分析工作流
- 创意写作提示
go
// 代码审查提示词
reviewPrompt := mcp.NewPrompt("code_review",
mcp.WithPromptDescription("Review code for best practices and issues"),
mcp.WithPromptArgument("code",
mcp.Required(),
mcp.Description("The code to review"),
),
mcp.WithPromptArgument("language",
mcp.Description("Programming language"),
),
)
// 数据分析提示词
analysisPrompt := mcp.NewPrompt("analyze_data",
mcp.WithPromptDescription("Analyze dataset and provide insights"),
mcp.WithPromptArgument("dataset_uri", mcp.Required()),
mcp.WithPromptArgument("focus_areas",
mcp.Description("Specific areas to focus analysis on"),
),
)传输层
传输层定义了 MCP 客户端和服务端之间的通信方式。MCP-Go 支持多种传输方法以适应不同的部署场景。
可用的传输方式:
Stdio - 标准输入/输出(最常用)
- 适用场景:本地工具、CLI 集成、桌面应用程序
- 优点:简单、安全、无需网络配置
- 缺点:仅限本地、单一客户端
Server-Sent Events (SSE) - 基于 HTTP 的流式传输
- 适用场景:Web 应用程序、实时更新
- 优点:Web 友好、实时、多客户端
- 缺点:HTTP 开销、单向流
HTTP - 传统请求/响应
- 适用场景:Web 服务、REST 风格 API
- 优点:标准协议、支持缓存、支持负载均衡
- 缺点:无实时更新、复杂度较高
go
// Stdio 传输(最常用)
server.ServeStdio(s)
// HTTP 传输
server.ServeHTTP(s, ":8080")
// SSE 传输
server.ServeSSE(s, ":8080")SDK 架构
MCP-Go 提供了清晰的架构,抽象了 MCP 协议的复杂性,同时在需要时给予你完全的控制能力。
服务端与客户端
理解何时构建服务端与客户端对于有效的 MCP 集成至关重要。
MCP 服务端:
- 用途:向 LLM 暴露工具、资源和提示词
- 用例:
- 数据库访问层
- 文件系统工具
- API 集成
- 自定义业务逻辑
- 特性:被动、响应请求、有状态
go
// 服务端示例 - 暴露功能
s := server.NewMCPServer("Database Tools", "1.0.0")
s.AddTool(queryTool, handleQuery)
s.AddResource(tableResource, handleTableAccess)
server.ServeStdio(s)MCP 客户端:
- 用途:连接并使用 MCP 服务端
- 用例:
- LLM 应用程序
- 编排工具
- 测试和调试
- 服务组合
- 特性:主动、发起请求、协调多个服务端
go
// 客户端示例 - 使用功能
client := client.NewStdioClient("database-server")
tools, _ := client.ListTools(ctx, mcp.ListToolsRequest{})
result, _ := client.CallTool(ctx, queryRequest)传输层
传输层抽象了通信协议,使你能够专注于业务逻辑而非协议细节。
主要优势:
- 协议无关:相同的服务端代码可用于任何传输方式
- 自动序列化:JSON 编组/解组自动处理
- 错误处理:传输特定错误被规范化
- 连接管理:自动重连和清理
go
// 相同的服务端可用于任何传输方式
s := server.NewMCPServer("My Server", "1.0.0")
// 运行时选择传输方式
switch transport {
case "stdio":
server.ServeStdio(s)
case "http":
server.ServeHTTP(s, ":8080")
case "sse":
server.ServeSSE(s, ":8080")
}会话管理
MCP-Go 自动处理会话管理,支持多个并发客户端并提供适当的隔离。
功能特性:
- 多客户端支持:多个 LLM 可以同时连接
- 会话隔离:每个客户端都有独立的状态
- 资源清理:客户端断开时自动清理
- 并发安全:跨所有会话的线程安全操作
会话生命周期:
- 初始化:客户端连接并交换能力
- 活跃:客户端发起请求,服务端响应
- 清理:连接关闭,资源释放
go
// 服务端自动处理多个会话
s := server.NewMCPServer("Multi-Client Server", "1.0.0",
server.WithHooks(&server.Hooks{
OnSessionStart: func(sessionID string) {
log.Printf("Client %s connected", sessionID)
},
OnSessionEnd: func(sessionID string) {
log.Printf("Client %s disconnected", sessionID)
},
}),
)状态管理模式:
go
// 每个会话的状态
type SessionState struct {
UserID string
Settings map[string]interface{}
}
var sessions = make(map[string]*SessionState)
func toolHandler(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
sessionID := server.GetSessionID(ctx)
state := sessions[sessionID]
// 使用会话特定的状态
return processWithState(state, req)
}
