@@ -7,17 +7,47 @@ import (
77 "os"
88 "os/signal"
99 "syscall"
10+ "time"
1011
1112 "github.com/voocel/mcp-sdk-go/protocol"
1213 "github.com/voocel/mcp-sdk-go/server"
1314 "github.com/voocel/mcp-sdk-go/transport/streamable"
1415)
1516
17+ // CalculationResult 计算结果
18+ type CalculationResult struct {
19+ Expression string `json:"expression" description:"原始表达式"`
20+ Result float64 `json:"result" description:"计算结果"`
21+ Operation string `json:"operation" description:"执行的运算"`
22+ Timestamp string `json:"timestamp" description:"计算时间"`
23+ }
24+
25+ // WeatherInfo 天气信息
26+ type WeatherInfo struct {
27+ Location string `json:"location" description:"地点"`
28+ Temperature float64 `json:"temperature" description:"温度(摄氏度)"`
29+ Humidity int `json:"humidity" description:"湿度百分比"`
30+ Condition string `json:"condition" description:"天气状况"`
31+ UpdateTime string `json:"update_time" description:"更新时间"`
32+ }
33+
34+ // ServerStats 服务器统计信息
35+ type ServerStats struct {
36+ Uptime string `json:"uptime" description:"运行时间"`
37+ RequestCount int `json:"request_count" description:"请求总数"`
38+ ActiveTools int `json:"active_tools" description:"活跃工具数"`
39+ Protocol string `json:"protocol" description:"协议版本"`
40+ }
41+
42+ var (
43+ serverStartTime = time .Now ()
44+ requestCounter = 0
45+ )
46+
1647func main () {
1748 ctx , cancel := context .WithCancel (context .Background ())
1849 defer cancel ()
1950
20- // 处理优雅关闭
2151 signalCh := make (chan os.Signal , 1 )
2252 signal .Notify (signalCh , os .Interrupt , syscall .SIGTERM )
2353 go func () {
@@ -26,10 +56,7 @@ func main() {
2656 cancel ()
2757 }()
2858
29- // 创建FastMCP服务器
3059 mcp := server .NewFastMCP ("Streamable HTTP 演示服务" , "1.0.0" )
31-
32- // 注册一个简单的问候工具
3360 mcp .Tool ("greet" , "问候用户" ).
3461 WithStringParam ("name" , "用户名称" , true ).
3562 WithStringParam ("language" , "语言(可选)" , false ).
@@ -54,26 +81,125 @@ func main() {
5481 return protocol .NewToolResultText (greeting ), nil
5582 })
5683
57- // 注册一个数学计算工具
58- mcp .Tool ("calculate" , "执行数学计算" ).
59- WithStringParam ("expression" , "数学表达式" , true ).
60- Handle (func (ctx context.Context , args map [string ]any ) (* protocol.CallToolResult , error ) {
61- expr , ok := args ["expression" ].(string )
84+ // 注册一个数学计算工具 - 结构化输出 (MCP 2025-06-18)
85+ err := mcp .Tool ("calculate" , "执行数学计算,返回结构化结果" ).
86+ WithStringParam ("operation" , "运算类型 (add, subtract, multiply, divide)" , true ).
87+ WithNumberParam ("a" , "第一个数字" , true ).
88+ WithNumberParam ("b" , "第二个数字" , true ).
89+ WithStructOutputSchema (CalculationResult {}). // 使用结构体自动生成输出模式
90+ HandleWithValidation (func (ctx context.Context , args map [string ]any ) (* protocol.CallToolResult , error ) {
91+ requestCounter ++
92+
93+ operation , _ := args ["operation" ].(string )
94+ a , _ := args ["a" ].(float64 )
95+ b , _ := args ["b" ].(float64 )
96+
97+ var result float64
98+ var opSymbol string
99+
100+ switch operation {
101+ case "add" :
102+ result = a + b
103+ opSymbol = "+"
104+ case "subtract" :
105+ result = a - b
106+ opSymbol = "-"
107+ case "multiply" :
108+ result = a * b
109+ opSymbol = "×"
110+ case "divide" :
111+ if b == 0 {
112+ return protocol .NewToolResultError ("除数不能为零" ), nil
113+ }
114+ result = a / b
115+ opSymbol = "÷"
116+ default :
117+ return protocol .NewToolResultError ("不支持的运算类型" ), nil
118+ }
119+
120+ calcResult := CalculationResult {
121+ Expression : fmt .Sprintf ("%.2f %s %.2f" , a , opSymbol , b ),
122+ Result : result ,
123+ Operation : operation ,
124+ Timestamp : time .Now ().Format (time .RFC3339 ),
125+ }
126+
127+ return protocol .NewToolResultTextWithStructured (
128+ fmt .Sprintf ("计算完成:%.2f %s %.2f = %.2f" , a , opSymbol , b , result ),
129+ calcResult ,
130+ ), nil
131+ })
132+ if err != nil {
133+ log .Fatal (err )
134+ }
135+
136+ err = mcp .SimpleStructuredTool (
137+ "get_weather" ,
138+ "获取指定城市的天气信息" ,
139+ protocol.JSONSchema {
140+ "type" : "object" ,
141+ "properties" : map [string ]any {
142+ "location" : map [string ]any {"type" : "string" , "description" : "地点" },
143+ "temperature" : map [string ]any {"type" : "number" , "description" : "温度(摄氏度)" },
144+ "humidity" : map [string ]any {"type" : "integer" , "description" : "湿度百分比" },
145+ "condition" : map [string ]any {"type" : "string" , "description" : "天气状况" },
146+ "update_time" : map [string ]any {"type" : "string" , "description" : "更新时间" },
147+ },
148+ "required" : []string {"location" , "temperature" , "humidity" , "condition" , "update_time" },
149+ },
150+ func (ctx context.Context , args map [string ]any ) (any , error ) {
151+ requestCounter ++
152+
153+ location , ok := args ["location" ].(string )
62154 if ! ok {
63- return protocol . NewToolResultError ( "参数 'expression' 必须是字符串" ), nil
155+ return nil , fmt . Errorf ( "location参数是必需的" )
64156 }
65157
66- // 简单的计算示例(实际应用中应该使用安全的表达式解析器)
67- result := fmt .Sprintf ("计算结果:%s = [此处应该是计算结果]" , expr )
68- return protocol .NewToolResultText (result ), nil
158+ conditions := []string {"晴天" , "多云" , "小雨" , "阴天" }
159+ weather := WeatherInfo {
160+ Location : location ,
161+ Temperature : 15 + float64 (len (location )% 20 ),
162+ Humidity : 50 + len (location )% 40 ,
163+ Condition : conditions [len (location )% len (conditions )],
164+ UpdateTime : time .Now ().Format ("2006-01-02 15:04:05" ),
165+ }
166+
167+ return weather , nil
168+ },
169+ )
170+ if err != nil {
171+ log .Fatal (err )
172+ }
173+
174+ // 注册服务器状态工具 - 演示动态结构化数据
175+ err = mcp .Tool ("server_stats" , "获取服务器运行状态" ).
176+ WithStructOutputSchema (ServerStats {}).
177+ HandleWithValidation (func (ctx context.Context , args map [string ]any ) (* protocol.CallToolResult , error ) {
178+ requestCounter ++
179+
180+ uptime := time .Since (serverStartTime )
181+ stats := ServerStats {
182+ Uptime : uptime .Round (time .Second ).String (),
183+ RequestCount : requestCounter ,
184+ ActiveTools : 4 , // greet, calculate, get_weather, server_stats
185+ Protocol : "Streamable HTTP (MCP 2025-06-18)" ,
186+ }
187+
188+ return protocol .NewToolResultTextWithStructured (
189+ fmt .Sprintf ("服务器已运行 %s,处理了 %d 个请求" , stats .Uptime , stats .RequestCount ),
190+ stats ,
191+ ), nil
69192 })
193+ if err != nil {
194+ log .Fatal (err )
195+ }
70196
71197 // 注册一个资源
72198 mcp .Resource ("info://server" , "服务器信息" , "获取服务器基本信息" ).
73199 Handle (func (ctx context.Context ) (* protocol.ReadResourceResult , error ) {
74200 info := `# Streamable HTTP MCP 服务器
75201
76- 这是一个演示 Streamable HTTP 传输协议的 MCP 服务器。
202+ 这是一个演示 Streamable HTTP 传输协议和结构化工具输出的 MCP 服务器。
77203
78204## 特性
79205
@@ -82,16 +208,35 @@ func main() {
82208- **会话管理**:支持有状态的会话
83209- **可恢复连接**:支持连接中断后的恢复
84210- **安全防护**:内置 DNS rebinding 攻击防护
211+ - **结构化输出**:支持类型化的工具结果 (MCP 2025-06-18)
85212
86213## 协议版本
87214
88- - MCP 版本:2025-03-26
215+ - MCP 版本:2025-06-18
89216- 传输协议:Streamable HTTP
217+ - 新特性:结构化工具输出
90218
91219## 可用工具
92220
93- 1. **greet** - 多语言问候工具
94- 2. **calculate** - 数学计算工具(演示用)
221+ 1. **greet** - 多语言问候工具(传统文本输出)
222+ 2. **calculate** - 数学计算工具(结构化输出演示)
223+ 3. **get_weather** - 天气查询工具(简化API演示)
224+ 4. **server_stats** - 服务器状态工具(动态数据演示)
225+
226+ ## 结构化输出示例
227+
228+ 工具现在可以返回类型化的JSON数据:
229+
230+ ` + "```" + `json
231+ {
232+ "content": [{"type": "text", "text": "人类可读的描述"}],
233+ "structuredContent": {
234+ "result": 42,
235+ "timestamp": "2025-01-15T10:30:00Z",
236+ "operation": "multiply"
237+ }
238+ }
239+ ` + "```" + `
95240
96241## 可用资源
97242
@@ -113,13 +258,17 @@ func main() {
113258 var content string
114259 switch topic {
115260 case "transport" :
116- content = "Streamable HTTP 是 MCP 2025-03-26 规范中的新传输协议 ,它统一了 HTTP 和 SSE 的优势。"
261+ content = "Streamable HTTP 是 MCP 2025-06-18 规范中的传输协议 ,它统一了 HTTP 和 SSE 的优势。"
117262 case "session" :
118263 content = "会话管理允许服务器在多个请求之间保持状态,提供更好的用户体验。"
119264 case "security" :
120265 content = "Streamable HTTP 包含多种安全机制,包括 Origin 验证和会话管理。"
266+ case "structured" :
267+ content = "结构化工具输出是 MCP 2025-06-18 的新特性,允许工具返回类型化的JSON数据,同时保持文本描述的可读性。"
268+ case "tools" :
269+ content = "本服务器演示了多种工具类型:传统文本输出(greet)、结构化输出(calculate)、简化API(get_weather)和动态数据(server_stats)。"
121270 default :
122- content = "Streamable HTTP 是一个现代化的 MCP 传输协议,提供了灵活的通信方式 。"
271+ content = "Streamable HTTP 是一个现代化的 MCP 传输协议,现在支持结构化工具输出功能 。"
123272 }
124273
125274 messages := []protocol.PromptMessage {
@@ -138,6 +287,8 @@ func main() {
138287 log .Println ("启动 Streamable HTTP MCP 服务器" )
139288 log .Println ("监听地址: http://localhost:8081" )
140289 log .Println ("传输协议: Streamable HTTP" )
290+ log .Println ("MCP版本: 2025-06-18 (支持结构化工具输出)" )
291+ log .Println ("可用工具: greet, calculate, get_weather, server_stats" )
141292
142293 if err := streamableServer .Serve (ctx ); err != nil && err != context .Canceled {
143294 log .Fatalf ("服务器错误: %v" , err )
0 commit comments