使用go搭建本地mcp实现AI选股小记
Model Context Protocol 即MCP,是一种协议,它允许大型语言模型LLMs访问自定义的工具和服务。比如可以使用trae中的智能体作为MCP客户端可以选择想 MCP Server 发起请求,以使用它们提供的工具。你可以自行添加 MCP Server,并添加到自定义的智能体中来使用在 trae 中,MCP Server 支持三种传输类型:stdio 传输,SSE 传输,Stream
·
【TypeScript】三分钟让 Trae、Cursor 用上你自己的 MCP
什么是MCP
Model Context Protocol 即MCP,是一种协议,它允许大型语言模型LLMs访问自定义的工具和服务。
比如可以使用trae中的智能体作为MCP客户端可以选择想 MCP Server 发起请求,以使用它们提供的工具。你可以自行添加 MCP Server,并添加到自定义的智能体中来使用
在 trae 中,MCP Server 支持三种传输类型:stdio 传输,SSE 传输,Streamable HTTP 传输
技术实现
编辑工具:vscode
插件:cline
go代码参考:使用Go语言基于MCP协议打造AI选股工具
//mcptest.go
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"time"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
"github.com/spf13/cast"
"github.com/tidwall/gjson"
)
type StockSearchRequest struct {
KeyWord string `json:"KeyWord"`
PageSize int `json:"pageSize"`
PageNo int `json:"pageNo"`
Fingerprint string `json:"fingerprint"`
MatchWord string `json:"matchWord"`
ShareToGuba bool `json:"shareToGuba"`
Timestamp string `json:"timestamp"`
RequestID string `json:"requestId"`
RemovedConditionIDList []interface{} `json:"removedConditionIdList"`
OwnSelectAll bool `json:"ownSelectAll"`
NeedCorrect bool `json:"needCorrect"`
Client string `json:"client"`
DxInfo []interface{} `json:"dxInfo"`
Biz string `json:"biz"`
Gids []interface{} `json:"gids"`
}
func main() {
mcpServer := server.NewMCPServer("mcp-server-ai-stock", "1.0.0", server.WithToolCapabilities(false))
queryStocks := mcp.NewTool("query_stocks",
mcp.WithDescription("智能选股:描述你期望的股票(自然语言选股),返回股票的最新交易数据。"),
mcp.WithString("keyword",
mcp.Description("选股条件,例:\n"+
"1. 股票或板块名称:宁德时代、比亚迪、新能源、AI、白酒\n"+
"2. 技术指标:MACD、5日均线、RSI、KDJ\n"+
"3. 财务条件:ROE>15%、净利润增长率>30%\n"+
"4. 复合条件:MACD金叉且成交量放大;股价在5日均线上方;不要ST股及不要退市股;不要科创板;不要北交所"),
),
)
mcpServer.AddTool(queryStocks, queryStocksHandler)
if err := server.ServeStdio(mcpServer); err != nil {
panic(err)
}
}
func queryStocksHandler(ctx context.Context, request mcp.CallToolRequest) (res *mcp.CallToolResult, err error) {
keyword := cast.ToString(cast.ToStringMap(request.Params.Arguments)["keyword"])
requestBody, err := json.Marshal(&StockSearchRequest{
PageNo: 1,
PageSize: 50,
KeyWord: keyword,
Fingerprint: "6d09ac0e7326d9299bb77ac2090dadd9",
Gids: []interface{}{},
Timestamp: cast.ToString(time.Now().UnixMilli()),
RequestID: "jVZgmtMhiPYtiDb7g2yferYT9aCrY1TA1758537136613",
NeedCorrect: true,
RemovedConditionIDList: []interface{}{},
DxInfo: []interface{}{},
Biz: "web_ai_select_stocks",
Client: "web",
})
if err != nil {
return &mcp.CallToolResult{Content: []mcp.Content{mcp.NewTextContent(fmt.Sprintf("序列化请求失败: %v", err))}}, nil
}
client := &http.Client{Timeout: 30 * time.Second}
req, err := http.NewRequestWithContext(ctx, "POST", "https://np-tjxg-g.eastmoney.com/api/smart-tag/stock/v3/pw/search-code", bytes.NewBuffer(requestBody))
if err != nil {
return &mcp.CallToolResult{Content: []mcp.Content{mcp.NewTextContent(fmt.Sprintf("创建请求失败: %v", err))}}, nil
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Origin", "https://xuangu.eastmoney.com")
req.Header.Set("Referer", "https://xuangu.eastmoney.com/")
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0")
resp, err := client.Do(req)
if err != nil {
return &mcp.CallToolResult{Content: []mcp.Content{mcp.NewTextContent(fmt.Sprintf("请求失败: %v", err))}}, nil
}
defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(resp.Body)
if err != nil {
return &mcp.CallToolResult{Content: []mcp.Content{mcp.NewTextContent(fmt.Sprintf("读取响应失败: %v", err))}}, nil
}
g := gjson.ParseBytes(body)
if g.Get("code").Int() != 100 {
return &mcp.CallToolResult{Content: []mcp.Content{mcp.NewTextContent(fmt.Sprintf("响应非100: %s", string(body)))}}, nil
}
if g.Get("data.result.total").Int() <= 0 {
return &mcp.CallToolResult{Content: []mcp.Content{mcp.NewTextContent("未找到符合条件的股票")}}, nil
}
content := parseSearchCodeResponse(g)
return &mcp.CallToolResult{Content: []mcp.Content{mcp.NewTextContent(content)}}, nil
}
func parseSearchCodeResponse(g gjson.Result) string {
var (
columns []string
b strings.Builder
)
_, _ = b.WriteString("## 筛选的股票数据\n")
g.Get("data.result.columns").ForEach(func(_, o gjson.Result) bool {
columns = append(columns, o.Get("key").String()) // 英文字段
_, _ = b.WriteString(o.Get("title").String() + o.Get("unit").String() + "|") // 中文表头
return true
})
g.Get("data.result.dataList").ForEach(func(_, o gjson.Result) bool {
_, _ = b.WriteString("\n|")
for _, column := range columns {
_, _ = b.WriteString(strings.ReplaceAll(o.Get(column).String(), "|", ",") + "|")
}
return true
})
return b.String()
}
上述代码实际是请求 东方财富 的开发API
执行命令,生成服务器端可执行文件
go build -o mcp-server mcptest.go
安装好cline插件之后,需要配置连接mcp服务器的脚本
增加如下配置
{
"mcpServers": {
"mcp-calculator-server": {
"command": "/Users/yourusername/Workspace/go/src/mcp-server/mcp-server"
}
}
}
配置成功后即可看到如下信息
结果
输入 “宁德时代”
会看到自动调用本地的mcp-server
输出
智能体美化后输出
输入 “MACD金叉且市盈率小于30”
输出
美化
更多推荐
所有评论(0)