diff --git a/mcpTimeServer/README.md b/mcpTimeServer/README.md deleted file mode 100644 index 87601ce..0000000 --- a/mcpTimeServer/README.md +++ /dev/null @@ -1,152 +0,0 @@ -# MCP Time Server - -一个使用Golang实现的MCP(Model Context Protocol)服务器,提供获取当前系统时间和SSE(Server-Sent Events)实时时间流功能。 - -## 项目概述 - -这个服务器实现了自定义的MCP协议,允许客户端通过HTTP接口获取当前系统时间,并且支持通过SSE技术订阅实时时间更新流。服务器使用slog库进行日志记录,日志仅输出到控制台。 - -## 功能特性 - -- 提供获取当前系统时间的MCP工具(`get_current_time`) -- 支持自定义时间格式 -- 实现SSE(Server-Sent Events)功能,提供实时时间流订阅(`subscribe_time_stream`) -- 使用slog进行结构化日志记录 -- 基于HTTP实现MCP协议 -- 提供健康检查接口 -- 支持优雅关闭 - -## 目录结构 - -``` -mcpTimeServer/ -├── main.go # 服务器主程序 -├── go.mod # Go模块定义 -├── install.sh # 安装脚本 -└── README.md # 项目说明文档 -``` - -## 安装与配置 - -### 前提条件 - -- Go 1.21或更高版本 - -### 安装步骤 - -1. 克隆项目或进入项目目录 - -2. 运行安装脚本: - ```bash - chmod +x install.sh - ./install.sh - ``` - - 安装脚本会检查Go环境、安装依赖并编译项目。 - -## 使用方法 - -### 启动服务器 - -```bash -./mcp_time_server -``` - -服务器启动后,会在8080端口监听HTTP请求。 - -## API说明 - -### MCP协议接口 - -#### 提交MCP请求 - -- **URL**: `/mcp/v1/submit` -- **方法**: `POST` -- **Content-Type**: `application/json` - -**请求体示例**: -```json -{ - "data": {"format": "2006-01-02 15:04:05"}, // 可选参数 - "type": "get_current_time", - "timestamp": 1699999999 -} -``` - -#### 可用工具 - -1. **get_current_time** - - **参数**: `format`(可选)- 时间格式字符串,使用Go的时间格式语法(如"2006-01-02 15:04:05") - - **返回结果**: - ```json - { - "current_time": "格式化的时间字符串", - "timestamp": 时间戳(Unix时间,秒) - } - ``` - -2. **subscribe_time_stream** - - **参数**: - - `interval`(可选)- 时间更新间隔(秒),默认为1秒 - - `format`(可选)- 时间格式字符串 - - **返回结果**: - ```json - { - "stream_id": "唯一的流标识符", - "sse_url": "http://localhost:8080/sse", - "interval": 更新间隔(秒) - } - ``` - -### SSE接口 - -- **URL**: `/sse` -- **方法**: `GET` -- **Content-Type**: `text/event-stream` - -连接后,服务器会以指定的间隔发送时间更新事件。 - -### 健康检查接口 - -- **URL**: `/health` -- **方法**: `GET` -- **返回**: 状态码200表示服务器正常运行 - -## 测试方法 - -服务器启动后,可以使用以下方式测试: - -1. **健康检查**: - ```bash - curl http://localhost:8080/health - ``` - -2. **获取当前时间**: - ```bash - curl -X POST http://localhost:8080/mcp/v1/submit -H 'Content-Type: application/json' -d '{"data":{},"type":"get_current_time","timestamp":'$(date +%s)'}' - ``` - -3. **使用自定义格式获取当前时间**: - ```bash - curl -X POST http://localhost:8080/mcp/v1/submit -H 'Content-Type: application/json' -d '{"data":{"format":"2006-01-02 15:04:05"},"type":"get_current_time","timestamp":'$(date +%s)'}' - ``` - -4. **订阅时间流**: - ```bash - curl http://localhost:8080/sse - ``` - 或直接在浏览器中访问 `http://localhost:8080/sse` - -## 依赖说明 - -- github.com/google/uuid v1.6.0:用于生成唯一标识符 - -## 注意事项 - -- 服务器默认监听在8080端口 -- 日志仅输出到控制台,不会写入文件 -- SSE连接会在客户端断开或服务器关闭时终止 - -## License - -MIT \ No newline at end of file diff --git a/mcpTimeServer/go.mod b/mcpTimeServer/go.mod deleted file mode 100644 index 458d85b..0000000 --- a/mcpTimeServer/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module mcpTimeServer - -go 1.21 - -require github.com/google/uuid v1.6.0 diff --git a/mcpTimeServer/install.sh b/mcpTimeServer/install.sh deleted file mode 100644 index df7862a..0000000 --- a/mcpTimeServer/install.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash - -# MCP Time Server 安装脚本 - -# 设置颜色 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # 无颜色 - -# 检查是否安装了Go -echo -e "${BLUE}检查Go环境...${NC}" -if ! command -v go &> /dev/null -then - echo -e "${RED}错误: 未安装Go。请先安装Go 1.21或更高版本。${NC}" - exit 1 -fi - -# 检查Go版本 -GO_VERSION=$(go version | awk '{print $3}' | sed 's/go//') -GO_MAJOR=$(echo $GO_VERSION | cut -d. -f1) -GO_MINOR=$(echo $GO_VERSION | cut -d. -f2) - -if [ $GO_MAJOR -lt 1 ] || ([ $GO_MAJOR -eq 1 ] && [ $GO_MINOR -lt 21 ]); then - echo -e "${RED}错误: Go版本过低 ($GO_VERSION)。请安装Go 1.21或更高版本。${NC}" - exit 1 -fi - -echo -e "${GREEN}已安装Go ($GO_VERSION)${NC}" - -# 检查当前目录 -echo -e "${BLUE}\n检查项目目录...${NC}" -if [ ! -f "main.go" ]; then - echo -e "${RED}错误: 请在包含main.go的项目根目录下运行此脚本。${NC}" - exit 1 -fi - -echo -e "${GREEN}项目目录正确${NC}" - -# 安装依赖 -echo -e "${BLUE}\n安装项目依赖...${NC}" -go mod tidy -if [ $? -ne 0 ]; then - echo -e "${RED}安装依赖失败,请检查网络连接。${NC}" - exit 1 -fi - -echo -e "${GREEN}依赖安装成功${NC}" - -# 编译项目 -echo -e "${BLUE}\n编译项目...${NC}" -go build -o mcp_time_server -if [ $? -ne 0 ]; then - echo -e "${RED}编译失败。${NC}" - exit 1 -fi - -chmod +x mcp_time_server -echo -e "${GREEN}编译成功,生成可执行文件: mcp_time_server${NC}" - -# 显示使用说明 -echo -e "\n${GREEN}安装完成!${NC}" -echo -e "${BLUE}\n使用说明:${NC}" -echo -e "1. 启动服务器: ./mcp_time_server" -echo -e "2. 服务器启动后,可以通过以下方式测试:" -echo -e " - 健康检查: curl http://localhost:8080/health" -echo -e " - 获取当前时间: curl -X POST http://localhost:8080/mcp/v1/submit -H 'Content-Type: application/json' -d '{\"data\":{},\"type\":\"get_current_time\",\"timestamp\":$(date +%s)}'" -echo -e " - 订阅时间流: 使用浏览器或SSE客户端访问 http://localhost:8080/sse" -echo -e "\n${YELLOW}注意: 服务器默认监听在8080端口。${NC}" -echo -e "\n${GREEN}MCP Time Server安装成功!${NC}" \ No newline at end of file diff --git a/mcpTimeServer/main.go b/mcpTimeServer/main.go deleted file mode 100644 index 98ec34b..0000000 --- a/mcpTimeServer/main.go +++ /dev/null @@ -1,385 +0,0 @@ -package main - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "log/slog" - "net/http" - "os" - "os/signal" - "sync" - "syscall" - "time" - - "github.com/google/uuid" -) - -// MCPRequest MCP请求结构体 -type MCPRequest struct { - Data interface{} `json:"data"` - Type string `json:"type"` - Metadata map[string]string `json:"metadata,omitempty"` - Timestamp int64 `json:"timestamp"` -} - -// MCPResponse MCP响应结构体 -type MCPResponse struct { - Success bool `json:"success"` - Message string `json:"message,omitempty"` - Data interface{} `json:"data,omitempty"` - RequestID string `json:"request_id,omitempty"` - Timestamp int64 `json:"timestamp"` -} - -// SSEClient SSE客户端连接管理 -type SSEClient struct { - ID string - Channel chan []byte -} - -// SSEManager SSE管理器 -type SSEManager struct { - clients map[string]*SSEClient - mutex sync.Mutex -} - -// NewSSEManager 创建新的SSE管理器 -func NewSSEManager() *SSEManager { - return &SSEManager{ - clients: make(map[string]*SSEClient), - } -} - -// AddClient 添加SSE客户端 -func (m *SSEManager) AddClient(clientID string) *SSEClient { - m.mutex.Lock() - defer m.mutex.Unlock() - - client := &SSEClient{ - ID: clientID, - Channel: make(chan []byte, 10), - } - m.clients[clientID] = client - - return client -} - -// RemoveClient 移除SSE客户端 -func (m *SSEManager) RemoveClient(clientID string) { - m.mutex.Lock() - defer m.mutex.Unlock() - - if client, exists := m.clients[clientID]; exists { - close(client.Channel) - delete(m.clients, clientID) - } -} - -// Broadcast 广播消息给所有SSE客户端 -func (m *SSEManager) Broadcast(message []byte) { - m.mutex.Lock() - defer m.mutex.Unlock() - - for _, client := range m.clients { - select { - case client.Channel <- message: - default: - // 如果客户端通道已满,跳过 - } - } -} - -// 格式化时间,处理可能的格式错误 -func formatTime(t time.Time, format string) (string, error) { - if format == "" { - return t.Format(time.RFC3339), nil - } - - // 尝试使用自定义格式 - formatted := t.Format(format) - if formatted == format { - // 如果格式化后的结果与格式字符串相同,说明格式无效 - return "", errors.New("无效的时间格式") - } - - return formatted, nil -} - -// 处理获取当前时间请求 -func handleGetCurrentTime(data map[string]interface{}) (map[string]interface{}, error) { - // 获取当前时间 - now := time.Now() - - // 获取可选的格式参数 - format, _ := data["format"].(string) - - // 格式化时间 - formattedTime, err := formatTime(now, format) - if err != nil { - // 如果格式无效,使用默认格式 - formattedTime = now.Format(time.RFC3339) - } - - // 返回结果 - result := map[string]interface{}{ - "current_time": formattedTime, - "timestamp": now.Unix(), - } - - return result, nil -} - -// 处理订阅时间流请求 -func handleSubscribeTimeStream(data map[string]interface{}) (map[string]interface{}, error) { - // 生成唯一的流ID - streamID := uuid.New().String() - - // 获取可选的间隔参数(默认1秒) - interval := 1.0 - if intervalVal, ok := data["interval"].(float64); ok { - if intervalVal > 0 { - interval = intervalVal - } - } - - // 获取可选的格式参数 - format, _ := data["format"].(string) - - // 存储订阅信息(实际项目中可能需要更复杂的存储机制) - // 这里我们只是返回流信息,实际的SSE连接会在/sse端点建立 - - // 返回结果 - result := map[string]interface{}{ - "stream_id": streamID, - "sse_url": "http://localhost:8080/sse", - "interval": interval, - "format": format, - } - - return result, nil -} - -// 处理MCP请求提交 -func handleSubmit(w http.ResponseWriter, r *http.Request) { - // 检查请求方法 - if r.Method != http.MethodPost { - http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) - return - } - - // 解析请求体 - var request MCPRequest - if err := json.NewDecoder(r.Body).Decode(&request); err != nil { - response := MCPResponse{ - Success: false, - Message: "Invalid request body", - Timestamp: time.Now().Unix(), - } - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) - return - } - - // 生成请求ID - requestID := uuid.New().String() - - // 根据工具类型处理请求 - var result map[string]interface{} - var err error - switch request.Type { - case "get_current_time": - // 确保data是map类型 - dataMap, ok := request.Data.(map[string]interface{}) - if !ok { - dataMap = make(map[string]interface{}) - } - result, err = handleGetCurrentTime(dataMap) - case "subscribe_time_stream": - // 确保data是map类型 - dataMap, ok := request.Data.(map[string]interface{}) - if !ok { - dataMap = make(map[string]interface{}) - } - result, err = handleSubscribeTimeStream(dataMap) - default: - err = errors.New("未知的工具类型") - } - - // 构建响应 - response := MCPResponse{ - Success: err == nil, - Message: func() string { if err != nil { return err.Error() } return "" }(), - Data: result, - RequestID: requestID, - Timestamp: time.Now().Unix(), - } - - // 返回响应 - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) - - // 记录日志 - slog.Debug("处理MCP请求", "request_id", requestID, "tool_type", request.Type, "success", err == nil) -} - -// 处理SSE连接 -func handleSSE(w http.ResponseWriter, r *http.Request, sseManager *SSEManager) { - // 设置响应头 - w.Header().Set("Content-Type", "text/event-stream") - w.Header().Set("Cache-Control", "no-cache") - w.Header().Set("Connection", "keep-alive") - w.Header().Set("Access-Control-Allow-Origin", "*") - - // 获取或生成客户端ID - clientID := r.URL.Query().Get("client_id") - if clientID == "" { - clientID = uuid.New().String() - } - - // 添加客户端到管理器 - client := sseManager.AddClient(clientID) - defer sseManager.RemoveClient(clientID) - - // 发送初始连接确认事件 - fmt.Fprintf(w, "event: connected\ndata: {\"client_id\":\"%s\"}\n\n", clientID) - flusher, ok := w.(http.Flusher) - if !ok { - slog.Error("不支持SSE", "client_id", clientID) - return - } - flusher.Flush() - - // 获取时间格式参数(如果有) - format := r.URL.Query().Get("format") - - // 获取时间间隔参数(如果有) - interval := 1.0 - if intervalStr := r.URL.Query().Get("interval"); intervalStr != "" { - fmt.Sscanf(intervalStr, "%f", &interval) - if interval <= 0 { - interval = 1.0 - } - } - - // 创建上下文用于取消操作 - ctx, cancel := context.WithCancel(r.Context()) - defer cancel() - - // 创建定时器 - ticker := time.NewTicker(time.Duration(interval * float64(time.Second))) - defer ticker.Stop() - - slog.Info("SSE连接已建立", "client_id", clientID, "interval", interval, "format", format) - - // 发送时间更新 - for { - select { - case <-ctx.Done(): - // 客户端断开连接 - slog.Info("SSE连接已断开", "client_id", clientID) - return - case now := <-ticker.C: - // 格式化时间 - var formattedTime string - if format == "" { - formattedTime = now.Format(time.RFC3339) - } else { - var err error - formattedTime, err = formatTime(now, format) - if err != nil { - // 如果格式无效,使用默认格式 - formattedTime = now.Format(time.RFC3339) - } - } - - // 创建时间更新事件 - timeData := map[string]interface{}{ - "current_time": formattedTime, - "timestamp": now.Unix(), - "interval": interval, - } - - // 转换为JSON - dataJSON, _ := json.Marshal(timeData) - - // 发送SSE事件 - fmt.Fprintf(w, "event: time_update\ndata: %s\n\n", string(dataJSON)) - flusher.Flush() - slog.Debug("发送SSE时间更新", "client_id", clientID, "time", formattedTime) - case message := <-client.Channel: - // 发送广播消息 - fmt.Fprintf(w, "event: broadcast\ndata: %s\n\n", string(message)) - flusher.Flush() - } - } -} - -// handleHealth 处理健康检查请求 -func handleHealth(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write([]byte("OK")) -} - -func main() { - // 设置slog日志,仅输出到控制台,不写入文件 - logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) - slog.SetDefault(logger) - - logger.Info("MCP Time Server 启动") - - // 创建SSE管理器 - sseManager := NewSSEManager() - - // 创建路由器 - r := http.NewServeMux() - - // 注册健康检查端点 - r.HandleFunc("/health", handleHealth) - - // 注册MCP提交端点 - r.HandleFunc("/mcp/v1/submit", handleSubmit) - - // 注册SSE端点 - r.HandleFunc("/sse", func(w http.ResponseWriter, r *http.Request) { - handleSSE(w, r, sseManager) - }) - - // 创建HTTP服务器 - srv := &http.Server{ - Addr: ":8080", - Handler: r, - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, - IdleTimeout: 120 * time.Second, - } - - // 启动服务器 - go func() { - logger.Info("MCP Time Server 启动成功", "address", ":8080") - if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { - logger.Error("服务器启动失败", "error", err) - os.Exit(1) - } - }() - - // 等待中断信号 - quit := make(chan os.Signal, 1) - signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) - <-quit - - logger.Info("MCP Time Server 正在关闭...") - - // 创建超时上下文 - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - // 优雅关闭服务器 - if err := srv.Shutdown(ctx); err != nil { - logger.Error("服务器关闭失败", "error", err) - os.Exit(1) - } - - logger.Info("MCP Time Server 已安全关闭") -} \ No newline at end of file diff --git a/mcpTimeServer/mcp_client_example b/mcpTimeServer/mcp_client_example deleted file mode 100755 index 42f1836..0000000 Binary files a/mcpTimeServer/mcp_client_example and /dev/null differ diff --git a/mcpTimeServer/mcp_client_example.go b/mcpTimeServer/mcp_client_example.go deleted file mode 100644 index 7e4d62d..0000000 --- a/mcpTimeServer/mcp_client_example.go +++ /dev/null @@ -1,190 +0,0 @@ -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "time" -) - -// 这里使用通用的map类型表示请求和响应,避免与main.go中的结构体冲突 - -func main() { - // 服务器地址 - serverURL := "http://localhost:8080" - - // 1. 测试健康检查 - testHealthCheck(serverURL) - - // 2. 测试获取当前时间(默认格式) - testGetCurrentTime(serverURL, "") - - // 3. 测试获取当前时间(自定义格式) - testGetCurrentTime(serverURL, "2006-01-02 15:04:05") - - // 4. 测试订阅时间流 - testSubscribeTimeStream(serverURL) -} - -// 测试健康检查 -func testHealthCheck(serverURL string) { - url := fmt.Sprintf("%s/health", serverURL) - resp, err := http.Get(url) - if err != nil { - fmt.Printf("健康检查请求失败: %v\n", err) - return - } - defer resp.Body.Close() - - if resp.StatusCode == http.StatusOK { - fmt.Println("✅ 健康检查成功: 服务器正常运行") - } else { - fmt.Printf("❌ 健康检查失败: 状态码 %d\n", resp.StatusCode) - } -} - -// 测试获取当前时间 -func testGetCurrentTime(serverURL string, format string) { - url := fmt.Sprintf("%s/mcp/v1/submit", serverURL) - - // 构建请求体 - requestBody := map[string]interface{}{ - "data": map[string]interface{}{}, - "type": "get_current_time", - "timestamp": time.Now().Unix(), - } - - // 添加格式参数(如果提供) - if format != "" { - data := requestBody["data"].(map[string]interface{}) - data["format"] = format - } - - // 序列化请求体 - jsonData, err := json.Marshal(requestBody) - if err != nil { - fmt.Printf("序列化请求体失败: %v\n", err) - return - } - - // 发送POST请求 - resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData)) - if err != nil { - fmt.Printf("发送请求失败: %v\n", err) - return - } - defer resp.Body.Close() - - // 读取响应 - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - fmt.Printf("读取响应失败: %v\n", err) - return - } - - // 解析响应为map - var response map[string]interface{} - if err := json.Unmarshal(body, &response); err != nil { - fmt.Printf("解析响应失败: %v\n", err) - return - } - - // 检查响应状态 - success, ok := response["success"].(bool) - if !ok || !success { - message := "未知错误" - if msg, ok := response["message"].(string); ok { - message = msg - } - fmt.Printf("❌ 获取当前时间失败: %s\n", message) - return - } - - // 提取数据 - data, ok := response["data"].(map[string]interface{}) - if !ok { - fmt.Println("❌ 响应数据格式错误") - return - } - - // 获取时间信息 - currentTime, _ := data["current_time"].(string) - timestamp, _ := data["timestamp"].(float64) - fmt.Printf("✅ 获取当前时间成功 (格式: %s):\n", format) - fmt.Printf(" 时间: %s\n", currentTime) - fmt.Printf(" 时间戳: %.0f\n", timestamp) -} - -// 测试订阅时间流 -func testSubscribeTimeStream(serverURL string) { - url := fmt.Sprintf("%s/mcp/v1/submit", serverURL) - - // 构建请求体 - requestBody := map[string]interface{}{ - "data": map[string]interface{}{ - "interval": 2, // 每2秒更新一次 - "format": "2006-01-02 15:04:05", - }, - "type": "subscribe_time_stream", - "timestamp": time.Now().Unix(), - } - - // 序列化请求体 - jsonData, err := json.Marshal(requestBody) - if err != nil { - fmt.Printf("序列化请求体失败: %v\n", err) - return - } - - // 发送POST请求 - resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData)) - if err != nil { - fmt.Printf("发送请求失败: %v\n", err) - return - } - defer resp.Body.Close() - - // 读取响应 - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - fmt.Printf("读取响应失败: %v\n", err) - return - } - - // 解析响应为map - var response map[string]interface{} - if err := json.Unmarshal(body, &response); err != nil { - fmt.Printf("解析响应失败: %v\n", err) - return - } - - // 检查响应状态 - success, ok := response["success"].(bool) - if !ok || !success { - message := "未知错误" - if msg, ok := response["message"].(string); ok { - message = msg - } - fmt.Printf("❌ 订阅时间流失败: %s\n", message) - return - } - - // 提取数据 - data, ok := response["data"].(map[string]interface{}) - if !ok { - fmt.Println("❌ 响应数据格式错误") - return - } - - // 获取流信息 - streamID, _ := data["stream_id"].(string) - sseURL, _ := data["sse_url"].(string) - interval, _ := data["interval"].(float64) - fmt.Printf("✅ 订阅时间流成功:\n") - fmt.Printf(" 流ID: %s\n", streamID) - fmt.Printf(" SSE URL: %s\n", sseURL) - fmt.Printf(" 更新间隔: %.0f秒\n", interval) - fmt.Println(" 提示: 可以使用curl或浏览器访问SSE URL来接收实时时间更新") -} \ No newline at end of file diff --git a/mcpTimeServer/mcp_time_server b/mcpTimeServer/mcp_time_server deleted file mode 100755 index 9105baf..0000000 Binary files a/mcpTimeServer/mcp_time_server and /dev/null differ diff --git a/mcp_server-py/INSTALL.md b/mcp_server-py/INSTALL.md deleted file mode 100644 index 0391be8..0000000 --- a/mcp_server-py/INSTALL.md +++ /dev/null @@ -1,186 +0,0 @@ -# MCP服务器 - pip安装指南 - -本文档提供了在不同环境下使用pip安装MCP服务器依赖包的详细步骤。 - -## 系统要求 - -- Python 3.8 或更高版本 -- pip 21.0 或更高版本 - -## 检查Python和pip版本 - -在开始安装之前,请先检查您的Python和pip版本: - -```bash -python --version # 或 python3 --version -pip --version # 或 pip3 --version -``` - -如果您的系统中没有安装Python或pip,请先安装它们。 - -## 安装依赖方法 - -### 方法1:使用requirements.txt直接安装 - -最简单的方法是直接使用我们提供的`requirements.txt`文件安装所有依赖: - -```bash -cd /home/geng/mydate/deploy.stack/mcp_server -pip install -r requirements.txt -``` - -如果您的系统中有多个Python版本,可能需要使用`pip3`: - -```bash -pip3 install -r requirements.txt -``` - -### 方法2:虚拟环境安装(推荐) - -为了避免依赖冲突,我们推荐在虚拟环境中安装MCP服务器: - -#### 创建虚拟环境 - -```bash -# 创建虚拟环境 -python -m venv venv - -# 激活虚拟环境 -# Linux/MacOS -source venv/bin/activate -# Windows -# venv\Scripts\activate -``` - -#### 在虚拟环境中安装依赖 - -```bash -pip install -r requirements.txt -``` - -### 方法3:手动安装各个包 - -如果您需要手动安装各个包,可以使用以下命令: - -```bash -# 安装Flask -pip install flask==3.0.3 - -# 安装OpenAI API客户端 -pip install openai==1.30.1 - -# 安装requests库 -pip install requests==2.31.0 - -# 安装dotenv(用于环境变量管理) -pip install python-dotenv==1.0.1 - -# 可选:安装JSON日志格式化库 -pip install python-json-logger==2.0.7 -``` - -## 使用国内镜像源加速安装 - -如果您在国内访问PyPI比较慢,可以使用国内镜像源加速安装: - -### 使用阿里云镜像源 - -```bash -pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ -``` - -### 使用清华大学镜像源 - -```bash -pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/ -``` - -### 使用华为云镜像源 - -```bash -pip install -r requirements.txt -i https://repo.huaweicloud.com/repository/pypi/simple/ -``` - -## 验证安装 - -安装完成后,您可以使用以下命令验证所有依赖是否正确安装: - -```bash -pip list | grep -E "flask|openai|requests|python-dotenv" -``` - -您应该能看到已安装的包及其版本。 - -## 安装常见问题 - -### 1. 权限错误 - -如果您遇到权限错误,可以尝试使用`--user`选项以用户权限安装: - -```bash -pip install -r requirements.txt --user -``` - -或者使用sudo(不推荐): - -```bash -sudo pip install -r requirements.txt -``` - -### 2. 版本冲突 - -如果遇到版本冲突,可以尝试更新pip: - -```bash -pip install --upgrade pip -``` - -然后重新安装依赖。 - -### 3. Python.h: No such file or directory - -如果在安装过程中遇到缺少Python开发文件的错误,可以安装Python开发包: - -#### Ubuntu/Debian - -```bash -sudo apt-get install python3-dev -``` - -#### CentOS/RHEL - -```bash -sudo yum install python3-devel -``` - -#### Fedora - -```bash -sudo dnf install python3-devel -``` - -## 升级依赖 - -当需要升级依赖到新版本时,可以使用以下命令: - -```bash -pip install --upgrade -r requirements.txt -``` - -## 卸载依赖 - -如果需要卸载所有依赖,可以使用以下命令: - -```bash -pip uninstall -r requirements.txt -y -``` - -## 生成新的requirements.txt - -如果您对项目依赖做了修改,可以生成新的requirements.txt文件: - -```bash -pip freeze > requirements.txt -``` - -注意:这将包含环境中所有已安装的包,建议在虚拟环境中执行此操作。 \ No newline at end of file diff --git a/mcp_server-py/README.md b/mcp_server-py/README.md deleted file mode 100644 index 1adc788..0000000 --- a/mcp_server-py/README.md +++ /dev/null @@ -1,214 +0,0 @@ -# MCP服务器 - OpenAPI对接版 - -## 简介 - -这是一个对接OpenAPI的MCP(Model Context Protocol)服务器实现,用于接收来自客户端的请求并调用OpenAI API进行处理和分析。本服务器特别为与`disk_inspection.py`硬盘巡检脚本配合使用而设计,可以自动分析硬盘健康状态报告。 - -## 目录结构 - -``` -mcp_server/ -├── config.toml # 配置文件 -├── mcp_server.py # 主程序文件 -└── README.md # 说明文档 -``` - -## 安装依赖 - -在运行MCP服务器之前,需要安装必要的Python依赖包: - -```bash -pip install flask openai -``` - -## 配置说明 - -### 配置文件 `config.toml` - -配置文件使用TOML格式,包含以下几个主要部分: - -1. **服务器配置** - ```toml - [server] - host = "0.0.0.0" # 监听地址,0.0.0.0表示所有网卡 - port = 8080 # 监听端口 - debug = false # 是否开启调试模式 - ``` - -2. **OpenAI API配置** - ```toml - [openai] - api_key = "your-api-key-here" # 请替换为您的OpenAI API密钥 - model = "gpt-3.5-turbo" # 使用的模型 - base_url = "https://api.openai.com/v1" # API基础URL - max_tokens = 2048 # 最大token数 - temperature = 0.7 # 温度参数 - ``` - -3. **日志配置** - ```toml - [logging] - level = "info" # 日志级别:debug, info, warn, error - format = "text" # 日志格式:text, json - file_path = "/var/log/mcp_server.log" # 日志文件路径 - ``` - -4. **安全配置** - ```toml - [security] - enable_auth = false # 是否启用认证 - # 如果启用认证,需配置以下参数 - # auth_token = "your-auth-token" # 认证令牌 - ``` - -## 运行MCP服务器 - -### 1. 修改配置文件 - -首先,编辑`config.toml`文件,设置您的OpenAI API密钥: - -```bash -vim /home/geng/mydate/deploy.stack/mcp_server/config.toml -``` - -找到`[openai]`部分,将`api_key`替换为您的实际API密钥。 - -### 2. 启动服务器 - -使用Python直接运行服务器: - -```bash -cd /home/geng/mydate/deploy.stack/mcp_server -python mcp_server.py -``` - -或者,您可以将其作为后台服务运行: - -```bash -nohup python mcp_server.py > /dev/null 2>&1 & -``` - -## 与 `disk_inspection.py` 的对接 - -已修改的`disk_inspection.py`脚本可以直接向MCP服务器提交硬盘巡检报告: - -### 1. 为`disk_inspection.py`安装依赖 - -```bash -pip install requests -``` - -### 2. 运行硬盘巡检脚本 - -```bash -python /home/geng/mydate/deploy.stack/crontab/disk_inspection.py -``` - -脚本会自动执行以下操作: -- 检查各个控制器的硬盘状态 -- 生成Markdown格式的报告 -- 将报告通过HTTP请求发送到MCP服务器 -- 接收并保存AI分析结果 - -### 手动提交数据(可选) - -如果需要手动提交数据,可以使用curl命令: - -```bash -curl -X POST -H 'Content-Type: application/json' -d @/root/mcp_data_日期.json http://localhost:8080/mcp/v1/submit -``` - -## API接口说明 - -### MCP提交接口 - -``` -POST /mcp/v1/submit -``` - -**请求体(JSON格式)**: -```json -{ - "type": "disk_inspection_report", - "timestamp": "2023-08-15T12:34:56.789012", - "content": "# 硬盘巡检报告\n..." -} -``` - -**响应(JSON格式)**: -```json -{ - "status": "success", - "result": { - "analysis": "分析结果...", - "processed_at": "2023-08-15T12:35:00.123456", - "original_type": "disk_inspection_report" - } -} -``` - -### 健康检查接口 - -``` -GET /health -``` - -**响应(JSON格式)**: -```json -{ - "status": "healthy" -} -``` - -## 故障排除 - -1. **API密钥错误** - - 确保`config.toml`中的OpenAI API密钥正确 - - 检查API密钥是否有足够的余额和权限 - -2. **连接失败** - - 确保MCP服务器正在运行 - - 检查防火墙设置,确保8080端口已开放 - - 验证`disk_inspection.py`中的MCP服务器URL是否正确 - -3. **权限问题** - - 确保运行服务器的用户有权限写入日志文件 - - 确保`disk_inspection.py`以root权限运行 - -## 定期运行设置 - -您可以将MCP服务器添加到系统服务中,确保其持续运行: - -1. 创建系统服务文件: - ```bash - sudo vim /etc/systemd/system/mcp_server.service - ``` - -2. 添加以下内容(根据实际路径修改): - ``` - [Unit] - Description=MCP Server for OpenAPI Integration - After=network.target - - [Service] - Type=simple - User=root - WorkingDirectory=/home/geng/mydate/deploy.stack/mcp_server - ExecStart=/usr/bin/python /home/geng/mydate/deploy.stack/mcp_server/mcp_server.py - Restart=on-failure - - [Install] - WantedBy=multi-user.target - ``` - -3. 启用并启动服务: - ```bash - sudo systemctl daemon-reload - sudo systemctl enable mcp_server - sudo systemctl start mcp_server - ``` - -4. 检查服务状态: - ```bash - sudo systemctl status mcp_server - ``` \ No newline at end of file diff --git a/mcp_server-py/config.toml b/mcp_server-py/config.toml deleted file mode 100644 index 748394b..0000000 --- a/mcp_server-py/config.toml +++ /dev/null @@ -1,27 +0,0 @@ -[server] -# MCP服务器配置 -host = "0.0.0.0" # 监听地址 -port = 8080 # 监听端口 -debug = false # 是否开启调试模式 - -[openai] -# OpenAI API配置 -api_key = "your-api-key-here" # OpenAI API密钥 -model = "gpt-3.5-turbo" # 使用的模型 -base_url = "https://api.openai.com/v1" # API基础URL -max_tokens = 2048 # 最大token数 -temperature = 0.7 # 温度参数 - -auto_approve = true # 是否自动批准工具调用请求 - -[logging] -# 日志配置 -level = "info" # 日志级别:debug, info, warn, error -format = "text" # 日志格式:text, json -file_path = "/var/log/mcp_server.log" # 日志文件路径 - -[security] -# 安全配置 -enable_auth = false # 是否启用认证 -# 如果启用认证,需配置以下参数 -# auth_token = "your-auth-token" # 认证令牌 \ No newline at end of file diff --git a/mcp_server-py/mcp_server.py b/mcp_server-py/mcp_server.py deleted file mode 100644 index 77ecb42..0000000 --- a/mcp_server-py/mcp_server.py +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: UTF-8 -*- - -import os -import sys -import logging -import json -import toml -import traceback -from flask import Flask, request, jsonify -import openai - -class MCPServer: - def __init__(self): - # 初始化应用 - self.app = Flask(__name__) - # 加载配置 - self.config = self.load_config() - # 配置日志 - self.setup_logging() - # 配置OpenAI客户端 - self.setup_openai() - # 注册路由 - self.register_routes() - - def load_config(self): - """加载配置文件""" - config_path = os.path.join(os.path.dirname(__file__), "config.toml") - if not os.path.exists(config_path): - print(f"错误:配置文件不存在: {config_path}") - sys.exit(1) - - with open(config_path, "r", encoding="utf-8") as f: - return toml.load(f) - - def setup_logging(self): - """配置日志系统""" - log_config = self.config.get("logging", {}) - log_level = getattr(logging, log_config.get("level", "info").upper()) - log_format = log_config.get("format", "text") - log_file = log_config.get("file_path", "/var/log/mcp_server.log") - - # 确保日志目录存在 - log_dir = os.path.dirname(log_file) - if log_dir and not os.path.exists(log_dir): - os.makedirs(log_dir, exist_ok=True) - - # 配置日志格式 - if log_format == "json": - formatter = logging.Formatter( - '{"time":"%(asctime)s", "level":"%(levelname)s", "message":"%(message)s"}' - ) - else: - formatter = logging.Formatter( - '%(asctime)s - %(name)s - %(levelname)s - %(message)s' - ) - - # 配置文件日志 - file_handler = logging.FileHandler(log_file, encoding="utf-8") - file_handler.setFormatter(formatter) - - # 配置控制台日志 - console_handler = logging.StreamHandler() - console_handler.setFormatter(formatter) - - # 获取根logger并配置 - logger = logging.getLogger() - logger.setLevel(log_level) - logger.addHandler(file_handler) - logger.addHandler(console_handler) - - self.logger = logging.getLogger("MCPServer") - - def setup_openai(self): - """配置OpenAI客户端""" - openai_config = self.config.get("openai", {}) - openai.api_key = openai_config.get("api_key") - - # 如果配置了自定义API基础URL - if "base_url" in openai_config: - openai.api_base = openai_config["base_url"] - - self.openai_config = openai_config - - def register_routes(self): - """注册API路由""" - @self.app.route("/mcp/v1/submit", methods=["POST"]) - def submit_data(): - """接收并处理MCP提交的数据""" - try: - # 获取请求数据 - data = request.get_json() - if not data: - self.logger.warning("接收到无效的JSON数据") - return jsonify({"error": "无效的JSON数据"}), 400 - - self.logger.info(f"接收到MCP提交请求,类型: {data.get('type')}") - - # 处理提交的数据 - result = self.process_submission(data) - - return jsonify({"status": "success", "result": result}) - except Exception as e: - self.logger.error(f"处理提交请求时出错: {str(e)}") - self.logger.debug(traceback.format_exc()) - return jsonify({"error": str(e)}), 500 - - @self.app.route("/health", methods=["GET"]) - def health_check(): - """健康检查接口""" - return jsonify({"status": "healthy"}), 200 - - def process_submission(self, data): - """处理提交的数据,调用OpenAI API进行分析""" - submission_type = data.get("type", "") - content = data.get("content", "") - timestamp = data.get("timestamp", "") - - # 根据数据类型生成不同的提示词 - if submission_type == "disk_inspection_report": - prompt = self.generate_disk_report_prompt(content) - else: - prompt = f"请分析以下数据(类型:{submission_type}):\n{content}" - - # 调用OpenAI API - response = self.call_openai_api(prompt) - - return { - "analysis": response, - "processed_at": self.get_current_timestamp(), - "original_type": submission_type - } - - def generate_disk_report_prompt(self, report_content): - """为硬盘巡检报告生成特定的提示词""" - return f"""你是一位专业的系统管理员,请分析以下硬盘巡检报告: - -{report_content} - -请提供详细的分析结果,包括: -1. 健康状态总结 -2. 异常项分析(如果有) -3. 潜在风险评估 -4. 维护建议 -5. 需要特别关注的问题(如果有)""" - - def call_openai_api(self, prompt): - """调用OpenAI API""" - try: - # 调用OpenAI ChatCompletion API - response = openai.ChatCompletion.create( - model=self.openai_config.get("model", "gpt-3.5-turbo"), - messages=[ - {"role": "system", "content": "你是一个专业的AI助手,帮助用户分析和处理各种数据。"}, - {"role": "user", "content": prompt} - ], - max_tokens=self.openai_config.get("max_tokens", 2048), - temperature=self.openai_config.get("temperature", 0.7) - ) - - # 提取回复内容 - return response["choices"][0]["message"]["content"].strip() - except Exception as e: - self.logger.error(f"调用OpenAI API时出错: {str(e)}") - raise - - def get_current_timestamp(self): - """获取当前时间戳""" - import datetime - return datetime.datetime.now().isoformat() - - def run(self): - """启动服务器""" - server_config = self.config.get("server", {}) - host = server_config.get("host", "0.0.0.0") - port = server_config.get("port", 8080) - debug = server_config.get("debug", False) - - self.logger.info(f"MCP服务器启动成功,监听地址: {host}:{port}") - self.logger.info(f"OpenAI API配置: 模型={self.openai_config.get('model')}") - - # 启动Flask服务器 - self.app.run(host=host, port=port, debug=debug) - -if __name__ == "__main__": - # 创建并运行MCP服务器 - server = MCPServer() - server.run() \ No newline at end of file diff --git a/mcp_server-py/requirements.txt b/mcp_server-py/requirements.txt deleted file mode 100644 index 76a198d..0000000 --- a/mcp_server-py/requirements.txt +++ /dev/null @@ -1,17 +0,0 @@ -# MCP服务器依赖包 -# 生成时间: "+str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))+" - -# Web框架 -flask==3.0.3 - -# OpenAI API客户端 -openai==1.30.1 - -# HTTP请求库 -requests==2.31.0 - -# 配置文件解析 -python-dotenv==1.0.1 - -# 可选依赖 - 用于日志格式化 -python-json-logger==2.0.7 \ No newline at end of file diff --git a/mcp_server_go/.dockerignore b/mcp_server_go/.dockerignore deleted file mode 100644 index 37ad6f0..0000000 --- a/mcp_server_go/.dockerignore +++ /dev/null @@ -1,41 +0,0 @@ -# 编译产物 -*.o -*.a -*.so -*.exe -*.out -mcp_server - -# 依赖缓存 -vendor/ - -# 日志文件 -logs/ -*.log - -# 测试文件 -*.test -coverage.out - -# IDE配置 -.vscode/ -.idea/ -*.swp -*.swo -*~ - -# 操作系统文件 -.DS_Store -Thumbs.db - -# 环境变量 -.env -.env.local -.env.development.local -.env.test.local -.env.production.local - -# 临时文件 -/tmp -/temp -.cache \ No newline at end of file diff --git a/mcp_server_go/README.md b/mcp_server_go/README.md deleted file mode 100644 index 8dba1b6..0000000 --- a/mcp_server_go/README.md +++ /dev/null @@ -1,297 +0,0 @@ -# MCP Server Go - -一个使用Golang实现的MCP(Master Control Program)服务器,能够对接开放的AI API(如OpenAI),提供数据分析和处理功能。 - -## 项目特点 - -- 基于Golang开发,高性能、低资源占用 -- 使用slog标准库进行日志管理,支持多级别、多格式日志输出 -- 使用TOML格式配置文件,配置简单明了 -- 支持对接OpenAI API,可扩展支持其他AI服务 -- 提供健康检查、Prometheus监控指标 -- 实现CORS跨域支持、请求速率限制、请求日志等中间件 -- 支持配置文件热重载 -- 优雅关闭机制 - -## 目录结构 - -``` -mcp_server_go/ -├── main.go # 主程序文件 -├── config.toml # 配置文件 -├── README.md # 项目说明文档 -├── go.mod # Go模块定义 -├── go.sum # 依赖版本锁定 -└── logs/ # 日志文件目录 - └── mcp_server.log # 日志文件 -``` - -## 配置说明 - -配置文件`config.toml`包含以下主要配置项: - -```toml -# 服务器基本配置 -[server] -listen_addr = "0.0.0.0:8080" # 监听地址和端口 -read_timeout = 30 # 读取超时时间(秒) -write_timeout = 30 # 写入超时时间(秒) -max_header_bytes = 1048576 # 最大请求头大小(字节) - -# OpenAI API 配置 -[openai] -api_key = "your_api_key_here" # OpenAI API密钥 -base_url = "https://api.openai.com/v1" # API基础URL -model = "gpt-3.5-turbo" # 使用的模型 -temperature = 0.7 # 生成内容的随机性 -max_tokens = 1000 # 最大生成token数 -request_timeout = 60 # 请求超时时间(秒) - -# 日志配置 -[logging] -level = "info" # 日志级别: debug, info, warn, error -format = "text" # 日志格式: text, json -output_path = "logs/mcp_server.log" # 日志文件路径 -max_size = 100 # 单个日志文件最大大小(MB) -max_age = 7 # 日志保留天数 -max_backups = 5 # 最大备份文件数 -compress = false # 是否压缩归档日志 - -# 安全配置 -[security] -allowed_origins = ["*"] # 允许的源 -allowed_methods = ["GET", "POST", "OPTIONS"] # 允许的HTTP方法 -allowed_headers = ["Content-Type", "Authorization"] # 允许的HTTP头 -``` - -## 安装与依赖 - -### 前提条件 - -- Go 1.21或更高版本 -- 有效的OpenAI API密钥(或其他兼容的AI服务API密钥) - -### 安装依赖 - -```bash -# 初始化Go模块(如果尚未初始化) -go mod init mcp_server_go - -# 安装依赖包 -go get github.com/sashabaranov/go-openai -go get github.com/spf13/viper -go get github.com/fsnotify/fsnotify -go get github.com/prometheus/client_golang/prometheus -go get github.com/prometheus/client_golang/prometheus/promhttp -go get github.com/google/uuid -go get golang.org/x/time/rate - -# 生成go.sum文件 -go mod tidy -``` - -## 运行方法 - -### 直接运行 - -```bash -# 确保配置文件正确设置 -# 启动服务器 -go run main.go -``` - -### 编译后运行 - -```bash -# 编译项目 -go build -o mcp_server -sudo chmod +x mcp_server - -# 运行编译后的二进制文件 -./mcp_server -``` - -### 作为系统服务运行 - -可以创建一个systemd服务文件来管理MCP服务器: - -```bash -sudo nano /etc/systemd/system/mcp_server.service -``` - -添加以下内容(根据实际路径修改): - -```ini -[Unit] -Description=MCP Server Go -After=network.target - -[Service] -Type=simple -User=your_user -WorkingDirectory=/home/geng/mydate/deploy.stack/mcp_server_go -ExecStart=/home/geng/mydate/deploy.stack/mcp_server_go/mcp_server -Restart=on-failure -RestartSec=5s - -[Install] -WantedBy=multi-user.target -``` - -然后启用并启动服务: - -```bash -sudo systemctl daemon-reload -sudo systemctl enable mcp_server -sudo systemctl start mcp_server -``` - -## API接口文档 - -### 健康检查接口 - -**GET /health** - -检查服务器和OpenAI连接状态 - -**响应示例**: - -```json -{ - "status": "ok", - "version": "1.0.0", - "timestamp": 1634567890, - "openai_health": true -} -``` - -### MCP数据提交接口 - -**POST /mcp/v1/submit** - -提交数据到MCP服务器进行处理和AI分析 - -**请求体示例**: - -```json -{ - "data": { - "disk_id": "sda", - "smart_data": { - "temperature": 38, - "power_on_hours": 12345, - "read_errors": 0, - "write_errors": 0 - }, - "performance_data": { - "read_speed": 120, - "write_speed": 90 - } - }, - "type": "disk_inspection", - "metadata": { - "server_id": "server-001", - "location": "data_center_a" - }, - "timestamp": 1634567890 -} -``` - -**响应示例**: - -```json -{ - "success": true, - "message": "数据提交成功", - "data": {"disk_id": "sda", ...}, // 原始提交的数据 - "ai_result": { - "analysis": "硬盘状态良好,温度正常,无错误记录。", - "recommendations": "建议定期进行数据备份,继续监控硬盘健康状态。", - "health_score": 98 - }, - "request_id": "req-1634567890-ab12cd34", - "timestamp": 1634567891 -} -``` - -### Prometheus监控指标 - -**GET /metrics** - -提供Prometheus格式的监控指标 - -## 日志说明 - -日志配置在`[logging]`部分,支持以下特性: - -- 可配置日志级别(debug、info、warn、error) -- 支持文本和JSON两种日志格式 -- 日志文件自动轮转(基于大小和时间) -- 同时输出到控制台和文件 - -## 安全配置 - -- 配置CORS策略,限制允许的源、方法和头部 -- 实现请求速率限制,防止滥用 -- 支持配置文件中的安全设置热重载 - -## 与disk_inspection.py的对接 - -MCP服务器可以直接接收`disk_inspection.py`脚本发送的数据: - -1. 确保`disk_inspection.py`中的`submit_to_mcp`方法配置正确的MCP服务器地址(http://localhost:8080/mcp/v1/submit) -2. 确保`disk_inspection.py`安装了requests依赖:`pip install requests` -3. 运行MCP服务器和disk_inspection.py脚本 - -## 故障排除 - -### 常见问题 - -1. **OpenAI API调用失败** - - 检查API密钥是否正确配置 - - 确认网络连接正常,特别是可以访问OpenAI API - - 查看日志文件获取详细错误信息 - -2. **配置文件不生效** - - 确认配置文件路径正确 - - 检查配置项格式是否符合TOML规范 - -3. **端口被占用** - - 修改`config.toml`中的`listen_addr`配置,使用其他可用端口 - -4. **请求速率限制** - - 如果遇到"请求过于频繁"的错误,可以调整代码中的速率限制参数 - -### 日志分析 - -日志文件默认位于`logs/mcp_server.log`,包含详细的请求处理信息、错误信息和OpenAI API调用情况。可以使用以下命令查看日志: - -```bash -# 实时查看日志 -tail -f logs/mcp_server.log - -# 搜索错误信息 -grep -i error logs/mcp_server.log -``` - -## 开发与扩展 - -### 添加新的AI服务支持 - -可以扩展代码以支持其他AI服务提供商,只需实现相应的客户端初始化和请求处理逻辑。 - -### 自定义数据处理逻辑 - -可以修改`analyzeWithOpenAI`函数,根据不同的数据类型和需求定制AI分析的提示词和处理逻辑。 - -### 添加新的API端点 - -可以在`main.go`中添加新的HTTP处理函数并注册到路由器,扩展服务器功能。 - -## 许可证 - -MIT License - -## 版本历史 - -- v1.0.0: 初始版本,支持OpenAI API对接、基本的MCP功能和监控 \ No newline at end of file diff --git a/mcp_server_go/config.toml b/mcp_server_go/config.toml deleted file mode 100644 index dda18ad..0000000 --- a/mcp_server_go/config.toml +++ /dev/null @@ -1,31 +0,0 @@ -# MCP Server Go 配置文件 -# 服务器基本配置 -[server] -listen_addr = "0.0.0.0:8080" -read_timeout = 30 write_timeout = 30 # 超时时间(秒) -max_header_bytes = 1048576 # 1MB - -# OpenAI API 配置 -[openai] -api_key = "your_api_key_here" # OpenAI API密钥 -base_url = "https://api.openai.com/v1" # API基础URL -model = "gpt-3.5-turbo" # 使用的模型 -temperature = 0.7 # 生成内容的随机性 -max_tokens = 1000 # 最大生成token数 -request_timeout = 60 # 请求超时时间(秒) - -# 日志配置 -[logging] -level = "info" # 日志级别: debug, info, warn, error -format = "text" # 日志格式: text, json -output_path = "logs/mcp_server.log" # 日志文件路径 -max_size = 100 # 单个日志文件最大大小(MB) -max_age = 7 # 日志保留天数 -max_backups = 5 # 最大备份文件数 -compress = false # 是否压缩归档日志 - -# 安全配置 -[security] -allowed_origins = ["*"] -allowed_methods = ["GET", "POST", "OPTIONS"] -allowed_headers = ["Content-Type", "Authorization"] \ No newline at end of file diff --git a/mcp_server_go/examples/client_example.go b/mcp_server_go/examples/client_example.go deleted file mode 100644 index 0d5150c..0000000 --- a/mcp_server_go/examples/client_example.go +++ /dev/null @@ -1,133 +0,0 @@ -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "time" -) - -// MCPRequest 定义MCP请求结构 -type MCPRequest struct { - Data interface{} `json:"data"` - Type string `json:"type"` - Metadata map[string]string `json:"metadata,omitempty"` - Timestamp int64 `json:"timestamp"` -} - -// MCPResponse 定义MCP响应结构 -type MCPResponse struct { - Success bool `json:"success"` - Message string `json:"message,omitempty"` - Data interface{} `json:"data,omitempty"` - AIResult interface{} `json:"ai_result,omitempty"` - RequestID string `json:"request_id,omitempty"` - Timestamp int64 `json:"timestamp"` -} - -func main() { - // 准备测试数据 - diskData := map[string]interface{}{ - "disk_id": "sda", - "smart_data": map[string]interface{}{ - "temperature": 38, - "power_on_hours": 12345, - "read_errors": 0, - "write_errors": 0, - "reallocated_sectors": 0, - }, - "performance_data": map[string]interface{}{ - "read_speed": 120, - "write_speed": 90, - "io_wait": 0.5, - }, - } - - // 创建MCP请求 - mcpRequest := MCPRequest{ - Data: diskData, - Type: "disk_inspection", - Metadata: map[string]string{"server_id": "test-server", "location": "test-lab"}, - Timestamp: time.Now().Unix(), - } - - // 序列化请求数据 - jsonData, err := json.Marshal(mcpRequest) - if err != nil { - fmt.Printf("序列化请求数据失败: %v\n", err) - return - } - - // 发送HTTP请求到MCP服务器 - resp, err := http.Post("http://localhost:8080/mcp/v1/submit", "application/json", bytes.NewBuffer(jsonData)) - if err != nil { - fmt.Printf("发送请求失败: %v\n", err) - fmt.Println("请确保MCP服务器正在运行,并且监听在正确的端口上") - return - } - defer resp.Body.Close() - - // 读取响应 - body, err := io.ReadAll(resp.Body) - if err != nil { - fmt.Printf("读取响应失败: %v\n", err) - return - } - - // 打印响应状态和内容 - fmt.Printf("响应状态码: %d\n", resp.StatusCode) - - // 如果响应成功,解析并显示详细信息 - if resp.StatusCode == http.StatusOK { - var mcpResponse MCPResponse - if err := json.Unmarshal(body, &mcpResponse); err != nil { - fmt.Printf("解析响应数据失败: %v\n", err) - fmt.Printf("原始响应内容: %s\n", string(body)) - return - } - - // 格式化输出响应数据 - fmt.Println("\nMCP服务器响应:") - fmt.Printf(" 成功状态: %v\n", mcpResponse.Success) - fmt.Printf(" 消息: %s\n", mcpResponse.Message) - fmt.Printf(" 请求ID: %s\n", mcpResponse.RequestID) - fmt.Printf(" 时间戳: %d (%s)\n", - mcpResponse.Timestamp, - time.Unix(mcpResponse.Timestamp, 0).Format("2006-01-02 15:04:05")) - - // 输出AI分析结果(如果有) - if mcpResponse.AIResult != nil { - fmt.Println("\nAI分析结果:") - aiResultJSON, _ := json.MarshalIndent(mcpResponse.AIResult, " ", " ") - fmt.Println(string(aiResultJSON)) - } - } else { - fmt.Printf("请求失败,响应内容: %s\n", string(body)) - } - - // 测试健康检查接口 - testHealthCheck() -} - -// 测试健康检查接口 -func testHealthCheck() { - fmt.Println("\n测试健康检查接口...") - - resp, err := http.Get("http://localhost:8080/health") - if err != nil { - fmt.Printf("健康检查失败: %v\n", err) - return - } - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - if err != nil { - fmt.Printf("读取健康检查响应失败: %v\n", err) - return - } - - fmt.Printf("健康检查状态码: %d\n", resp.StatusCode) - fmt.Printf("健康检查响应: %s\n", string(body)) -} diff --git a/mcp_server_go/go.mod b/mcp_server_go/go.mod deleted file mode 100644 index e11992a..0000000 --- a/mcp_server_go/go.mod +++ /dev/null @@ -1,34 +0,0 @@ -module mcp_server_go - -go 1.25.0 - -require ( - github.com/fsnotify/fsnotify v1.9.0 - github.com/google/uuid v1.6.0 - github.com/prometheus/client_golang v1.23.2 - github.com/sashabaranov/go-openai v1.41.1 - github.com/spf13/viper v1.21.0 - golang.org/x/time v0.13.0 -) - -require ( - github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/go-viper/mapstructure/v2 v2.4.0 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/pelletier/go-toml/v2 v2.2.4 // indirect - github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.66.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect - github.com/sagikazarmark/locafero v0.11.0 // indirect - github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect - github.com/spf13/afero v1.15.0 // indirect - github.com/spf13/cast v1.10.0 // indirect - github.com/spf13/pflag v1.0.10 // indirect - github.com/subosito/gotenv v1.6.0 // indirect - go.yaml.in/yaml/v2 v2.4.2 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/sys v0.35.0 // indirect - golang.org/x/text v0.28.0 // indirect - google.golang.org/protobuf v1.36.8 // indirect -) diff --git a/mcp_server_go/install.sh b/mcp_server_go/install.sh deleted file mode 100644 index 6b98cf0..0000000 --- a/mcp_server_go/install.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/bash - -# MCP Server Go 安装脚本 - -# 设置颜色 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # 无颜色 - -# 检查是否安装了Go -echo -e "${BLUE}检查Go环境...${NC}" -if ! command -v go &> /dev/null -then - echo -e "${RED}错误: 未安装Go。请先安装Go 1.21或更高版本。${NC}" - exit 1 -fi - -# 检查Go版本 -GO_VERSION=$(go version | awk '{print $3}' | sed 's/go//') -GO_MAJOR=$(echo $GO_VERSION | cut -d. -f1) -GO_MINOR=$(echo $GO_VERSION | cut -d. -f2) - -if [ $GO_MAJOR -lt 1 ] || ([ $GO_MAJOR -eq 1 ] && [ $GO_MINOR -lt 21 ]); then - echo -e "${RED}错误: Go版本过低 ($GO_VERSION)。请安装Go 1.21或更高版本。${NC}" - exit 1 -fi - -echo -e "${GREEN}已安装Go ($GO_VERSION)${NC}" - -# 检查当前目录 -echo -e "${BLUE}\n检查项目目录...${NC}" -if [ ! -f "main.go" ]; then - echo -e "${RED}错误: 请在包含main.go的项目根目录下运行此脚本。${NC}" - exit 1 -fi - -echo -e "${GREEN}项目目录正确${NC}" - -# 创建日志目录 -echo -e "${BLUE}\n创建日志目录...${NC}" -mkdir -p logs -echo -e "${GREEN}日志目录已创建: logs/${NC}" - -# 安装依赖 -echo -e "${BLUE}\n安装项目依赖...${NC}" -if [ ! -f "go.mod" ]; then - echo -e "${YELLOW}未找到go.mod文件,正在初始化Go模块...${NC}" - go mod init mcp_server_go -fi - -go mod tidy -if [ $? -ne 0 ]; then - echo -e "${RED}安装依赖失败,请检查网络连接和go.mod文件。${NC}" - exit 1 -fi - -echo -e "${GREEN}依赖安装成功${NC}" - -# 编译项目 -echo -e "${BLUE}\n编译项目...${NC}" -go build -o mcp_server -if [ $? -ne 0 ]; then - echo -e "${RED}编译失败,请检查代码是否有错误。${NC}" - exit 1 -fi - -chmod +x mcp_server -echo -e "${GREEN}编译成功: mcp_server (可执行文件)${NC}" - -# 检查配置文件 -echo -e "${BLUE}\n检查配置文件...${NC}" -if [ ! -f "config.toml" ]; then - echo -e "${YELLOW}警告: 未找到config.toml文件。请根据config.toml.example创建配置文件。${NC}" -else - # 检查是否设置了API密钥 - API_KEY=$(grep "api_key" config.toml | awk -F'=' '{print $2}' | tr -d ' "') - if [ "$API_KEY" = "your_api_key_here" ]; then - echo -e "${YELLOW}警告: 配置文件中的API密钥尚未设置,请编辑config.toml并填入有效的OpenAI API密钥。${NC}" - else - echo -e "${GREEN}配置文件已找到,API密钥已设置${NC}" - fi -fi - -# 创建systemd服务文件 -echo -e "${BLUE}\n创建systemd服务文件 (可选)...${NC}" -read -p "是否创建systemd服务文件以便作为系统服务运行?(y/n): " CREATE_SERVICE - -if [[ $CREATE_SERVICE == [Yy]* ]]; then - # 获取当前路径 - CURRENT_DIR=$(pwd) - # 获取当前用户 - CURRENT_USER=$(whoami) - - # 创建systemd服务文件 - SERVICE_FILE="/etc/systemd/system/mcp_server.service" - - echo -e "${YELLOW}创建systemd服务文件: $SERVICE_FILE${NC}" - cat > mcp_server.service << EOF -[Unit] -Description=MCP Server Go -After=network.target - -[Service] -Type=simple -User=$CURRENT_USER -WorkingDirectory=$CURRENT_DIR -ExecStart=$CURRENT_DIR/mcp_server -Restart=on-failure -RestartSec=5s - -[Install] -WantedBy=multi-user.target -EOF - - echo -e "${BLUE}\n请使用以下命令安装systemd服务:${NC}" - echo -e "sudo mv mcp_server.service $SERVICE_FILE" - echo -e "sudo systemctl daemon-reload" - echo -e "sudo systemctl enable mcp_server" - echo -e "sudo systemctl start mcp_server" -fi - -# 显示启动说明 -echo -e "\n${GREEN}安装完成!${NC}" -echo -e "${BLUE}\n使用说明:${NC}" -echo -e "1. 确保编辑config.toml文件,设置正确的OpenAI API密钥" -echo -e "2. 直接运行: ./mcp_server" -echo -e "3. 或按照上述说明设置为系统服务" -echo -e "\n${YELLOW}注意: 首次运行前,请确保config.toml中的配置正确无误。${NC}" - -echo -e "\n${GREEN}MCP Server Go安装成功!${NC}" \ No newline at end of file diff --git a/mcp_server_go/main.go b/mcp_server_go/main.go deleted file mode 100644 index 23b8c9e..0000000 --- a/mcp_server_go/main.go +++ /dev/null @@ -1,492 +0,0 @@ -package main - -import ( - "context" - "encoding/json" - "fmt" - "io" - "log/slog" - "net/http" - "os" - "os/signal" - "path/filepath" - "strings" - "syscall" - "time" - - "github.com/fsnotify/fsnotify" - "github.com/google/uuid" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/spf13/viper" - "golang.org/x/time/rate" - - openai "github.com/sashabaranov/go-openai" -) - -// Config 结构体用于存储配置 -type Config struct { - Server ServerConfig `mapstructure:"server"` - OpenAI OpenAIConfig `mapstructure:"openai"` - Logging LoggingConfig `mapstructure:"logging"` - Security SecurityConfig `mapstructure:"security"` -} - -// ServerConfig 服务器配置 -type ServerConfig struct { - ListenAddr string `mapstructure:"listen_addr"` - ReadTimeout int `mapstructure:"read_timeout"` - WriteTimeout int `mapstructure:"write_timeout"` - MaxHeaderBytes int `mapstructure:"max_header_bytes"` -} - -// OpenAIConfig OpenAI API配置 -type OpenAIConfig struct { - APIKey string `mapstructure:"api_key"` - BaseURL string `mapstructure:"base_url"` - Model string `mapstructure:"model"` - Temperature float64 `mapstructure:"temperature"` - MaxTokens int `mapstructure:"max_tokens"` - RequestTimeout int `mapstructure:"request_timeout"` -} - -// LoggingConfig 日志配置 -type LoggingConfig struct { - Level string `mapstructure:"level"` - Format string `mapstructure:"format"` - OutputPath string `mapstructure:"output_path"` - MaxSize int `mapstructure:"max_size"` - MaxAge int `mapstructure:"max_age"` - MaxBackups int `mapstructure:"max_backups"` - Compress bool `mapstructure:"compress"` -} - -// SecurityConfig 安全配置 -type SecurityConfig struct { - AllowedOrigins []string `mapstructure:"allowed_origins"` - AllowedMethods []string `mapstructure:"allowed_methods"` - AllowedHeaders []string `mapstructure:"allowed_headers"` -} - -// MCPRequest MCP请求结构体 -type MCPRequest struct { - Data interface{} `json:"data"` - Type string `json:"type"` - Metadata map[string]string `json:"metadata,omitempty"` - Timestamp int64 `json:"timestamp"` -} - -// MCPResponse MCP响应结构体 -type MCPResponse struct { - Success bool `json:"success"` - Message string `json:"message,omitempty"` - Data interface{} `json:"data,omitempty"` - AIResult interface{} `json:"ai_result,omitempty"` - RequestID string `json:"request_id,omitempty"` - Timestamp int64 `json:"timestamp"` -} - -var ( - config Config - logger *slog.Logger - openaiClient *openai.Client - // 速率限制器 - limiter = rate.NewLimiter(rate.Limit(10), 20) - // Prometheus指标 - requestCounter = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "mcp_server_requests_total", - Help: "Total number of MCP server requests", - }, - []string{"endpoint", "status"}, - ) - requestDuration = prometheus.NewHistogramVec( - prometheus.HistogramOpts{ - Name: "mcp_server_request_duration_seconds", - Help: "Duration of MCP server requests in seconds", - Buckets: prometheus.DefBuckets, - }, - []string{"endpoint"}, - ) -) - -func init() { - // 注册Prometheus指标 - prometheus.MustRegister(requestCounter) - prometheus.MustRegister(requestDuration) -} - -// 加载配置 -func loadConfig() error { - viper.SetConfigName("config") - viper.SetConfigType("toml") - viper.AddConfigPath(".") - viper.AddConfigPath("/etc/mcp_server/") - viper.AddConfigPath("$HOME/.mcp_server/") - viper.AddConfigPath("$HOME/.config/mcp_server/") - - if err := viper.ReadInConfig(); err != nil { - return fmt.Errorf("读取配置文件失败: %w", err) - } - - // 打印当前使用的配置文件路径(使用标准库输出,因为logger可能还未初始化) - fmt.Printf("成功加载配置文件: %s\n", viper.ConfigFileUsed()) - - if err := viper.Unmarshal(&config); err != nil { - return fmt.Errorf("解析配置文件失败: %w", err) - } - - // 配置文件热重载 - viper.WatchConfig() - viper.OnConfigChange(func(e fsnotify.Event) { - logger.Info("配置文件已变更,重新加载", "file", e.Name) - if err := viper.Unmarshal(&config); err != nil { - logger.Error("重新解析配置文件失败", "error", err) - } - // 重新初始化OpenAI客户端 - initOpenAIClient() - }) - - return nil -} - -// 初始化日志 -func initLogger() error { - // 创建日志目录 - logDir := filepath.Dir(config.Logging.OutputPath) - if err := os.MkdirAll(logDir, 0755); err != nil { - return fmt.Errorf("创建日志目录失败: %w", err) - } - - // 打开日志文件 - logFile, err := os.OpenFile( - config.Logging.OutputPath, - os.O_CREATE|os.O_WRONLY|os.O_APPEND, - 0644, - ) - if err != nil { - return fmt.Errorf("打开日志文件失败: %w", err) - } - - // 设置日志级别 - var logLevel slog.Level - switch config.Logging.Level { - case "debug": - logLevel = slog.LevelDebug - case "warn": - logLevel = slog.LevelWarn - case "error": - logLevel = slog.LevelError - default: - logLevel = slog.LevelInfo - } - - // 创建日志器,同时输出到控制台和文件 - logger = slog.New(slog.NewTextHandler( - io.MultiWriter(os.Stdout, logFile), - &slog.HandlerOptions{Level: logLevel}, - )) - slog.SetDefault(logger) - - return nil -} - -// 初始化OpenAI客户端 -func initOpenAIClient() { - cfg := openai.DefaultConfig(config.OpenAI.APIKey) - if config.OpenAI.BaseURL != "" { - cfg.BaseURL = config.OpenAI.BaseURL - } - openaiClient = openai.NewClientWithConfig(cfg) -} - -// 创建CORS中间件 -func corsMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // 设置CORS头 - for _, origin := range config.Security.AllowedOrigins { - w.Header().Set("Access-Control-Allow-Origin", origin) - } - w.Header().Set("Access-Control-Allow-Methods", strings.Join(config.Security.AllowedMethods, ",")) - w.Header().Set("Access-Control-Allow-Headers", strings.Join(config.Security.AllowedHeaders, ",")) - w.Header().Set("Access-Control-Allow-Credentials", "true") - - // 处理预检请求 - if r.Method == "OPTIONS" { - w.WriteHeader(http.StatusOK) - return - } - - next.ServeHTTP(w, r) - }) -} - -// 速率限制中间件 -func rateLimitMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !limiter.Allow() { - http.Error(w, "请求过于频繁,请稍后再试", http.StatusTooManyRequests) - return - } - next.ServeHTTP(w, r) - }) -} - -// 日志中间件 -func loggingMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - startTime := time.Now() - logger.Info("收到请求", - slog.String("method", r.Method), - slog.String("path", r.URL.Path), - slog.String("remote_addr", r.RemoteAddr), - ) - - wrappedWriter := &responseWriter{ - ResponseWriter: w, - statusCode: http.StatusOK, - } - - next.ServeHTTP(wrappedWriter, r) - - duration := time.Since(startTime) - logger.Info("请求处理完成", - slog.String("method", r.Method), - slog.String("path", r.URL.Path), - slog.Int("status", wrappedWriter.statusCode), - slog.Duration("duration", duration), - ) - }) -} - -// 响应写入器包装器,用于捕获状态码 -type responseWriter struct { - http.ResponseWriter - statusCode int -} - -func (rw *responseWriter) WriteHeader(code int) { - rw.statusCode = code - rw.ResponseWriter.WriteHeader(code) -} - -// 健康检查端点 -func healthCheckHandler(w http.ResponseWriter, r *http.Request) { - start := time.Now() - defer func() { - requestDuration.WithLabelValues("/health").Observe(time.Since(start).Seconds()) - }() - - w.Header().Set("Content-Type", "application/json") - - // 检查OpenAI客户端连接 - oaiHealthy := false - if openaiClient != nil { - // 创建一个轻量级的测试请求 - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) - defer cancel() - - _, err := openaiClient.ListModels(ctx) - oaiHealthy = (err == nil) - } - - response := map[string]interface{}{ - "status": "ok", - "version": "1.0.0", - "timestamp": time.Now().Unix(), - "openai_health": oaiHealthy, - } - - json.NewEncoder(w).Encode(response) - requestCounter.WithLabelValues("/health", "200").Inc() -} - -// MCP数据提交端点 -func submitHandler(w http.ResponseWriter, r *http.Request) { - start := time.Now() - defer func() { - requestDuration.WithLabelValues("/mcp/v1/submit").Observe(time.Since(start).Seconds()) - }() - - // 生成请求ID - requestID := fmt.Sprintf("req-%d-%s", time.Now().UnixNano(), uuid.New().String()[:8]) - logger.Info("处理MCP提交请求", slog.String("request_id", requestID)) - - // 解析请求体 - var mcpRequest MCPRequest - if err := json.NewDecoder(r.Body).Decode(&mcpRequest); err != nil { - logger.Error("解析请求体失败", slog.String("request_id", requestID), slog.Any("error", err)) - http.Error(w, "无效的请求体", http.StatusBadRequest) - requestCounter.WithLabelValues("/mcp/v1/submit", "400").Inc() - return - } - - // 设置默认时间戳 - if mcpRequest.Timestamp == 0 { - mcpRequest.Timestamp = time.Now().Unix() - } - - // 调用OpenAI API进行分析 - aIResult, err := analyzeWithOpenAI(r.Context(), mcpRequest, requestID) - if err != nil { - logger.Error("OpenAI API调用失败", slog.String("request_id", requestID), slog.Any("error", err)) - http.Error(w, "AI分析失败", http.StatusInternalServerError) - requestCounter.WithLabelValues("/mcp/v1/submit", "500").Inc() - return - } - - // 构建响应 - response := MCPResponse{ - Success: true, - Message: "数据提交成功", - Data: mcpRequest.Data, - AIResult: aIResult, - RequestID: requestID, - Timestamp: time.Now().Unix(), - } - - // 发送响应 - w.Header().Set("Content-Type", "application/json") - if err := json.NewEncoder(w).Encode(response); err != nil { - logger.Error("发送响应失败", slog.String("request_id", requestID), slog.Any("error", err)) - } - - requestCounter.WithLabelValues("/mcp/v1/submit", "200").Inc() - logger.Info("MCP提交请求处理完成", slog.String("request_id", requestID)) -} - -// 使用OpenAI API进行数据分析 -func analyzeWithOpenAI(ctx context.Context, request MCPRequest, requestID string) (interface{}, error) { - // 准备超时上下文 - timeoutCtx, cancel := context.WithTimeout(ctx, time.Duration(config.OpenAI.RequestTimeout)*time.Second) - defer cancel() - - // 将请求数据转换为字符串 - dataJSON, err := json.Marshal(request.Data) - if err != nil { - return nil, fmt.Errorf("数据序列化失败: %w", err) - } - - // 构建提示词 - prompt := fmt.Sprintf(`请分析以下数据并提供见解: - -数据类型: %s - -数据内容: -%s - -请提供结构化的分析结果。`, request.Type, string(dataJSON)) - - // 创建聊天完成请求 - chatReq := openai.ChatCompletionRequest{ - Model: config.OpenAI.Model, - Messages: []openai.ChatCompletionMessage{ - { - Role: openai.ChatMessageRoleSystem, - Content: "你是一个数据分析助手,负责分析和解读各种类型的数据。", - }, - { - Role: openai.ChatMessageRoleUser, - Content: prompt, - }, - }, - Temperature: float32(config.OpenAI.Temperature), - MaxTokens: config.OpenAI.MaxTokens, - } - - // 调用OpenAI API - logger.Debug("调用OpenAI API", slog.String("request_id", requestID), slog.String("model", config.OpenAI.Model)) - resp, err := openaiClient.CreateChatCompletion(timeoutCtx, chatReq) - if err != nil { - return nil, fmt.Errorf("OpenAI API调用失败: %w", err) - } - - // 解析AI响应 - if len(resp.Choices) == 0 { - return nil, fmt.Errorf("OpenAI未返回有效结果") - } - - // 尝试将响应内容解析为JSON - var aiResult interface{} - if err := json.Unmarshal([]byte(resp.Choices[0].Message.Content), &aiResult); err != nil { - // 如果解析失败,直接返回原始文本 - aiResult = resp.Choices[0].Message.Content - } - - logger.Debug("OpenAI API调用成功", slog.String("request_id", requestID), slog.Int("token_usage", resp.Usage.TotalTokens)) - - return aiResult, nil -} - -// 主函数 -func main() { - // 加载配置 - if err := loadConfig(); err != nil { - fmt.Fprintf(os.Stderr, "加载配置失败: %v\n", err) - os.Exit(1) - } - - // 初始化日志 - if err := initLogger(); err != nil { - fmt.Fprintf(os.Stderr, "初始化日志失败: %v\n", err) - os.Exit(1) - } - - // 初始化OpenAI客户端 - initOpenAIClient() - - logger.Info("MCP服务器启动", slog.String("listen_addr", config.Server.ListenAddr)) - - // 创建路由器 - r := http.NewServeMux() - - // 注册健康检查端点 - r.HandleFunc("/health", healthCheckHandler) - - // 注册MCP提交端点 - r.HandleFunc("/mcp/v1/submit", submitHandler) - - // 注册Prometheus指标端点 - r.Handle("/metrics", promhttp.Handler()) - - // 创建中间件链 - handler := loggingMiddleware(rateLimitMiddleware(corsMiddleware(r))) - - // 创建HTTP服务器 - srv := &http.Server{ - Addr: config.Server.ListenAddr, - Handler: handler, - ReadTimeout: time.Duration(config.Server.ReadTimeout) * time.Second, - WriteTimeout: time.Duration(config.Server.WriteTimeout) * time.Second, - IdleTimeout: 120 * time.Second, - } - - // 启动服务器 - go func() { - if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { - logger.Error("服务器启动失败", slog.Any("error", err)) - os.Exit(1) - } - }() - - logger.Info("MCP服务器已成功启动") - - // 等待中断信号 - quit := make(chan os.Signal, 1) - signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) - <-quit - - logger.Info("MCP服务器正在关闭...") - - // 创建超时上下文 - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - // 优雅关闭服务器 - if err := srv.Shutdown(ctx); err != nil { - logger.Error("服务器关闭失败", slog.Any("error", err)) - os.Exit(1) - } - - logger.Info("MCP服务器已安全关闭") -} diff --git a/mcptime/go.mod b/mcptime/go.mod deleted file mode 100644 index 2c3386f..0000000 --- a/mcptime/go.mod +++ /dev/null @@ -1,17 +0,0 @@ -module mcptime - -go 1.25.0 - -require github.com/mark3labs/mcp-go v0.39.1 - -require ( - github.com/bahlo/generic-list-go v0.2.0 // indirect - github.com/buger/jsonparser v1.1.1 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/invopop/jsonschema v0.13.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/spf13/cast v1.7.1 // indirect - github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect - github.com/yosida95/uritemplate/v3 v3.0.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/mcptime/main.go b/mcptime/main.go deleted file mode 100644 index 60751af..0000000 --- a/mcptime/main.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - "context" - "fmt" - "log" - "time" - - "github.com/mark3labs/mcp-go/mcp" - "github.com/mark3labs/mcp-go/server" -) - -func main() { - s := server.NewMCPServer( - "Time Service", - "1.0.0", - server.WithResourceCapabilities(true, true), - server.WithLogging(), - ) - - tool_time := mcp.NewTool("get_current_time", - mcp.WithDescription("获取当前系统时间,返回格式:yyyy-MM-dd HH:mm:ss"), - ) - s.AddTool(tool_time, currentTimeHandler) - - tool_date := mcp.NewTool("get_current_date", - mcp.WithDescription("get current date,output format:yyyy-MM-dd"), - ) - s.AddTool(tool_date, currentDateHandler) - - if err := server.ServeStdio(s); err != nil { - fmt.Printf("Server start fail: %v\n", err) - } else { - log.Println("Time MCP start") - } -} - -func currentTimeHandler(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { - currentTime := time.Now().Format("2006-01-02 15:04:05") - return mcp.NewToolResultText(fmt.Sprintf("%s", currentTime)), nil -} - -func currentDateHandler(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { - currentTime := time.Now().Format("2006-01-02") - return mcp.NewToolResultText(fmt.Sprintf("%s", currentTime)), nil -}