增加供应商智能添加功能

This commit is contained in:
2026-09-04 00:09:32 +08:00
parent d8936d9730
commit 20be7f4817
29 changed files with 4317 additions and 1476 deletions
+243
View File
@@ -0,0 +1,243 @@
// 内置演示 MCP 服务(stdio 传输)
// 提供 get_time / calculate / weather_query / echo 等工具,用于验证「MCP 市场 → 会话工具调用」全链路。
// 运行:go run ./cmd/demo-mcp 或直接运行已编译二进制 bin/demo-mcp
package main
import (
"context"
"encoding/json"
"fmt"
"math"
"strings"
"time"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
func toolResultText(text string) *mcp.CallToolResult {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.TextContent{Type: "text", Text: text},
},
}
}
func main() {
srv := server.NewMCPServer("demo-mcp", "1.0.0")
// 1. 当前时间
srv.AddTool(mcp.NewTool(
"get_time",
mcp.WithDescription("获取服务器当前日期和时间(含星期),不需要参数"),
), func(_ context.Context, _ mcp.CallToolRequest) (*mcp.CallToolResult, error) {
now := time.Now()
weekdays := []string{"日", "一", "二", "三", "四", "五", "六"}
return toolResultText(fmt.Sprintf("当前时间:%s(星期%s)",
now.Format("2006-01-02 15:04:05"), weekdays[int(now.Weekday())])), nil
})
// 2. 计算器
srv.AddTool(mcp.NewTool(
"calculate",
mcp.WithDescription("计算一个数学表达式,支持 + - * / % 与括号。例如:2+3*4"),
mcp.WithString("expression", mcp.Required(), mcp.Description("数学表达式字符串")),
), func(_ context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
expr := req.GetArguments()["expression"]
exprStr, _ := expr.(string)
exprStr = strings.TrimSpace(exprStr)
if exprStr == "" {
return toolResultText("错误:expression 参数不能为空"), nil
}
val, err := safeEval(exprStr)
if err != nil {
return toolResultText("错误:" + err.Error()), nil
}
return toolResultText(fmt.Sprintf("%s = %v", exprStr, val)), nil
})
// 3. 模拟天气
srv.AddTool(mcp.NewTool(
"weather_query",
mcp.WithDescription("查询指定城市的模拟天气信息(演示数据,非真实天气)"),
mcp.WithString("city", mcp.Required(), mcp.Description("城市名称,如 北京、上海、连云港")),
), func(_ context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
city, _ := req.GetArguments()["city"].(string)
city = strings.TrimSpace(city)
if city == "" {
city = "未知城市"
}
conditions := []string{"晴", "多云", "小雨", "阴", "晴转多云"}
cond := conditions[int(time.Now().Unix())%len(conditions)]
temp := 18 + int(time.Now().Unix())%15
return toolResultText(fmt.Sprintf("【%s】今天 %s,气温 %d℃,空气质量:良(模拟数据)", city, cond, temp)), nil
})
// 4. 回声
srv.AddTool(mcp.NewTool(
"echo",
mcp.WithDescription("原样返回你输入的文字,用于测试"),
mcp.WithString("text", mcp.Required(), mcp.Description("要回显的文字")),
), func(_ context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
text, _ := req.GetArguments()["text"].(string)
return toolResultText("echo: " + text), nil
})
// 5. 获取用户信息(演示带对象参数的 JSON 参数)
srv.AddTool(mcp.NewTool(
"get_user_profile",
mcp.WithDescription("获取用户画像信息(演示),可指定姓名与年龄"),
mcp.WithString("name", mcp.Required(), mcp.Description("姓名")),
mcp.WithNumber("age", mcp.Description("年龄")),
), func(_ context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
args := req.GetArguments()
name, _ := args["name"].(string)
age, _ := args["age"].(float64)
out, _ := json.Marshal(map[string]interface{}{
"name": name,
"age": int(age),
"role": "演示用户",
"note": "这是一条来自内置演示 MCP 服务的测试数据",
})
return toolResultText(string(out)), nil
})
if err := server.ServeStdio(srv); err != nil {
panic(err)
}
}
// safeEval 极简安全表达式求值(仅支持数字与 + - * / % 和括号)
func safeEval(expr string) (float64, error) {
parser := &exprParser{s: expr}
parser.skipSpace()
v, err := parser.parseExpr()
if err != nil {
return 0, err
}
parser.skipSpace()
if parser.pos < len(parser.s) {
return 0, fmt.Errorf("无法解析的表达式(非法字符)")
}
if math.IsInf(v, 0) || math.IsNaN(v) {
return 0, fmt.Errorf("计算结果无效")
}
return v, nil
}
type exprParser struct {
s string
pos int
}
func (p *exprParser) skipSpace() {
for p.pos < len(p.s) && (p.s[p.pos] == ' ' || p.s[p.pos] == '\t') {
p.pos++
}
}
func (p *exprParser) peek() byte {
if p.pos < len(p.s) {
return p.s[p.pos]
}
return 0
}
func (p *exprParser) parseExpr() (float64, error) {
v, err := p.parseTerm()
if err != nil {
return 0, err
}
for {
p.skipSpace()
c := p.peek()
if c == '+' || c == '-' {
p.pos++
rhs, err := p.parseTerm()
if err != nil {
return 0, err
}
if c == '+' {
v += rhs
} else {
v -= rhs
}
} else {
return v, nil
}
}
}
func (p *exprParser) parseTerm() (float64, error) {
v, err := p.parseFactor()
if err != nil {
return 0, err
}
for {
p.skipSpace()
c := p.peek()
if c == '*' || c == '/' || c == '%' {
p.pos++
rhs, err := p.parseFactor()
if err != nil {
return 0, err
}
switch c {
case '*':
v *= rhs
case '/':
if rhs == 0 {
return 0, fmt.Errorf("除数不能为 0")
}
v /= rhs
case '%':
if rhs == 0 {
return 0, fmt.Errorf("取模除数不能为 0")
}
v = math.Mod(v, rhs)
}
} else {
return v, nil
}
}
}
func (p *exprParser) parseFactor() (float64, error) {
p.skipSpace()
c := p.peek()
if c == '(' {
p.pos++
v, err := p.parseExpr()
if err != nil {
return 0, err
}
p.skipSpace()
if p.peek() != ')' {
return 0, fmt.Errorf("缺少右括号")
}
p.pos++
return v, nil
}
return p.parseNumber()
}
func (p *exprParser) parseNumber() (float64, error) {
start := p.pos
for p.pos < len(p.s) {
c := p.s[p.pos]
if (c >= '0' && c <= '9') || c == '.' {
p.pos++
} else {
break
}
}
if start == p.pos {
return 0, fmt.Errorf("表达式格式错误(无法识别的字符)")
}
raw := p.s[start:p.pos]
var v float64
if _, err := fmt.Sscanf(raw, "%g", &v); err != nil {
return 0, fmt.Errorf("数字格式错误: %s", raw)
}
return v, nil
}