MCP 简介

模型上下文协议(Model Context Protocol,简称 MCP)是一种开放标准,旨在标准化大型语言模型(LLM)与外部数据源和工具之间的交互方式。

Anthropic202411 月推出,MCP 通过定义统一的接口,使 AI 应用能够安全、灵活地访问和操作本地及远程数据资源。

Transports(传输层)

消息格式

MCP 协议使用 JSON-RPC 2.0 作为消息传输格式:

Request 请求:

1
2
3
4
5
6
{
"jsonrpc": "2.0",
"id": 1,
"method": "string",
"params": {}
}

Response 响应:

1
2
3
4
5
6
{
"jsonrpc": "2.0",
"id": 1,
"result": {},
"error": { "code": 123, "message": "错误描述" }
}

Notification 通知:

1
2
3
4
5
{
"jsonrpc": "2.0",
"method": "string",
"params": {}
}

内置传输类型

标准输入/输出(stdio)

stdio 通过标准输入输出流实现通信,适用于本地集成与命令行工具。

Go server 示例:

1
2
3
4
s := server.NewMCPServer("My Server", "1.0.0")
if err := server.ServeStdio(s); err != nil {
log.Fatalf("Server error: %v", err)
}

Server-Sent Events (SSE)

SSE 通过 HTTP POST 请求实现客户端到服务器通信,支持服务器到客户端流式传输。

Go server 示例:

1
2
sseServer := server.NewSSEServer(s)
err := sseServer.Start(":8080")

MCP 的通用架构

MCP 遵循 CS 架构:

  • Host 主机:发起连接 LLM 的应用程序
  • MCP Client 客户端:与 MCP Server 保持 1:1 连接
  • MCP Server 服务器:提供资源、提示和工具

MCP 客户端

Roots 根

Roots 用于界定服务器可操作的边界,可以是文件系统路径或 HTTP URL。

1
2
3
4
5
6
7
8
{
"roots": [
{
"uri": "file:///home/workspace/frontend",
"name": "Frontend Repository"
}
]
}

Sampling 采样

采样允许服务器通过客户端向 LLM 请求补全结果,实现更复杂的代理行为。

工作原理:

  1. 服务器发送 sampling/createMessage 请求
  2. 客户端审核请求
  3. 客户端向 LLM 发送采样请求
  4. 客户端审核结果
  5. 客户端返回最终结果

采样请求示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "当前目录下有哪些文件?"
}
}
],
"maxTokens": 100,
"systemPrompt": "你是一名文件系统助手。"
}

MCP 服务器

Prompts 提示词

提示词允许服务器定义可复用的提示词模板和工作流。

结构定义:

1
2
3
4
5
6
7
8
9
10
11
{
"name": "analyze-code",
"description": "分析代码以发现潜在改进点",
"arguments": [
{
"name": "language",
"description": "编程语言",
"required": true
}
]
}

Resources 资源

资源是 MCP 协议的核心原语,服务器通过它向客户端提供可读数据。

资源 URI 格式:

1
2
3
[协议]://[主机]/[路径]
file:///home/user/documents/go.pdf
postgres://database/user/schema

Tools 工具

工具是 MCP 协议中暴露给 LLM 的可执行功能。

工具结构:

1
2
3
4
5
6
7
8
9
10
11
12
{
"name": "github_create_issue",
"description": "在 GitHub 创建 Issue",
"inputSchema": {
"type": "object",
"properties": {
"title": { "type": "string" },
"body": { "type": "string" },
"labels": { "type": "array", "items": { "type": "string" } }
}
}
}

原语控制层级

原语 控制方 描述 示例
Prompts 用户控制 交互式模板 斜杠命令(/command)
Resources 应用控制 上下文数据 文件内容、git 历史
Tools 模型控制 功能接口 API 请求、文件写入

服务器实现(Go)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package main

import (
"context"
"errors"
"fmt"
"os"

"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)

func main() {
s := server.NewMCPServer("Server Demo", "1.0.0")

// 添加工具
calculatorTool := mcp.NewTool("calculate",
mcp.WithDescription("执行基本的算术运算"),
mcp.WithString("operation",
mcp.Required(),
mcp.Description("运算类型"),
mcp.Enum("add", "subtract", "multiply", "divide"),
),
mcp.WithNumber("x", mcp.Required(), mcp.Description("第一个数字")),
mcp.WithNumber("y", mcp.Required(), mcp.Description("第二个数字")),
)

s.AddTool(calculatorTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
op := request.Params.Arguments["operation"].(string)
x := request.Params.Arguments["x"].(float64)
y := request.Params.Arguments["y"].(float64)

var result float64
switch op {
case "add": result = x + y
case "subtract": result = x - y
case "multiply": result = x * y
case "divide":
if y == 0 { return nil, errors.New("不允许除以零") }
result = x / y
}
return mcp.FormatNumberResult(result), nil
})

// 添加资源
resource := mcp.NewResource("docs://readme", "项目说明文档")
s.AddResource(resource, func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
content, err := os.ReadFile("README.md")
if err != nil { return nil, err }
return []mcp.ResourceContents{
mcp.TextResourceContents{URI: "docs://readme", Text: string(content)},
}, nil
})

// 启动服务
if err := server.ServeStdio(s); err != nil {
fmt.Printf("Server error: %v\n", err)
}
}

客户端实现(Go)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package main

import (
"context"
"fmt"
"time"

"github.com/mark3labs/mcp-go/client"
"github.com/mark3labs/mcp-go/mcp"
)

func main() {
mcpClient, err := client.NewStdioMCPClient("./server", []string{})
if err != nil { panic(err) }
defer mcpClient.Close()

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

// 初始化
initResult, err := mcpClient.Initialize(ctx, mcp.InitializeRequest{})
fmt.Printf("服务器信息: %s %s\n",
initResult.ServerInfo.Name, initResult.ServerInfo.Version)

// 获取工具列表
tools, _ := mcpClient.ListTools(ctx, mcp.ListToolsRequest{})
for _, tool := range tools.Tools {
fmt.Printf("- %s: %s\n", tool.Name, tool.Description)
}

// 调用工具
result, _ := mcpClient.CallTool(ctx, mcp.CallToolRequest{
Params: mcp.CallToolParams{
Name: "calculate",
Arguments: map[string]any{"operation": "add", "x": 1, "y": 1},
},
})
fmt.Println("结果:", result.Content[0].(mcp.TextContent).Text)
}

运行结果:

1
2
3
初始化成功,服务器信息: Server Demo 1.0.0
可用工具: calculate
调用工具结果: 2.00

小结

本文介绍了 MCP 协议的核心内容:

  • 客户端原语:roots(根路径)、sampling(采样)
  • 服务器原语:prompts(提示词)、resources(资源)、tools(工具)
  • Server 原语控制层级:用户控制、应用控制、模型控制

通过 Go 语言的客户端与服务器示例,帮助开发者快速理解和应用该协议。