#
tokens: 6848/50000 7/7 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── config.json
├── Dockerfile
├── go.mod
├── go.sum
├── LICENSE
├── main.go
├── Makefile
├── README.md
├── smithery.yaml
├── wecom_test.go
└── wecom.go
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
1 | mcp-webcombot-server
2 | dist/
3 | docs/
```

--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |     "mcpServers": {
 3 |       "mcp-difyworkflow-server": {
 4 |         "command": "mcp-wecombot-server", // mcp-wecombot-server bainary Path or mcp-wecombot-server 
 5 |         "env": {
 6 |           "WECOM_BOT_WEBHOOK_KEY":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx"
 7 |          }
 8 |       }
 9 |     }
10 | }
```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | # Smithery configuration file: https://smithery.ai/docs/deployments
 2 | 
 3 | startCommand:
 4 |   type: stdio
 5 |   configSchema:
 6 |     # JSON Schema defining the configuration options for the MCP.
 7 |     type: object
 8 |     required:
 9 |       - wecomBotWebhookKey
10 |     properties:
11 |       wecomBotWebhookKey:
12 |         type: string
13 |         description: The webhook key for the WeCom Bot server.
14 |   commandFunction:
15 |     # A function that produces the CLI command to start the MCP on stdio.
16 |     |-
17 |     config => ({ command: 'mcp-wecombot-server', env: { WECOM_BOT_WEBHOOK_KEY: config.wecomBotWebhookKey } })
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | # Build stage
 2 | FROM golang:1.21-alpine AS builder
 3 | 
 4 | # Set the working directory inside the container
 5 | WORKDIR /app
 6 | 
 7 | # Copy go.mod and go.sum files first for dependency resolution
 8 | COPY go.mod go.sum ./
 9 | 
10 | # Download dependencies
11 | RUN go mod download
12 | 
13 | # Copy the entire source code into the container
14 | COPY . .
15 | 
16 | # Build the binary for Linux
17 | RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o dist/mcp-wecombot-server_linux_amd64 .
18 | 
19 | # Final stage
20 | FROM alpine:latest
21 | 
22 | # Set working directory
23 | WORKDIR /app
24 | 
25 | # Copy the compiled binary from the builder stage
26 | COPY --from=builder /app/dist/mcp-wecombot-server_linux_amd64 /usr/local/bin/mcp-wecombot-server
27 | 
28 | # Expose any ports the application requires, if necessary
29 | # EXPOSE <port>
30 | 
31 | # Set the entrypoint to the compiled binary
32 | ENTRYPOINT ["mcp-wecombot-server"]
```

--------------------------------------------------------------------------------
/wecom_test.go:
--------------------------------------------------------------------------------

```go
  1 | package main
  2 | 
  3 | import (
  4 | 	"encoding/json"
  5 | 	"fmt"
  6 | 	"io"
  7 | 	"net/http"
  8 | 	"net/http/httptest"
  9 | 	"os"
 10 | 	"testing"
 11 | )
 12 | 
 13 | // MockWeComServer is a mock server for testing WeComBot.
 14 | type MockWeComServer struct {
 15 | 	*httptest.Server
 16 | }
 17 | 
 18 | // test upload file need to setting your's test key
 19 | var testkey = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx"
 20 | 
 21 | // NewMockWeComServer creates a new mock WeCom server.
 22 | func NewMockWeComServer() *MockWeComServer {
 23 | 	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 24 | 		if r.Method == "POST" {
 25 | 			body, _ := io.ReadAll(r.Body)
 26 | 			fmt.Println(string(body))
 27 | 			w.Header().Set("Content-Type", "application/json")
 28 | 			w.WriteHeader(http.StatusOK)
 29 | 			json.NewEncoder(w).Encode(map[string]interface{}{
 30 | 				"errcode": 0,
 31 | 				"errmsg":  "ok",
 32 | 			})
 33 | 		}
 34 | 	})
 35 | 
 36 | 	server := httptest.NewServer(handler)
 37 | 	return &MockWeComServer{Server: server}
 38 | }
 39 | 
 40 | // TestSendText tests the SendText method.
 41 | func TestSendText(t *testing.T) {
 42 | 	mockServer := NewMockWeComServer()
 43 | 	defer mockServer.Close()
 44 | 
 45 | 	bot := NewWeComBot(mockServer.URL, "")
 46 | 	err := bot.SendText("Hello, WeCom!", []string{}, []string{})
 47 | 	if err != nil {
 48 | 		t.Errorf("SendText failed: %v", err)
 49 | 	}
 50 | }
 51 | 
 52 | // TestSendMarkdown tests the SendMarkdown method.
 53 | func TestSendMarkdown(t *testing.T) {
 54 | 	mockServer := NewMockWeComServer()
 55 | 	defer mockServer.Close()
 56 | 
 57 | 	bot := NewWeComBot(mockServer.URL, "")
 58 | 	err := bot.SendMarkdown("## Hello, WeCom!\nThis is a markdown message.")
 59 | 	if err != nil {
 60 | 		t.Errorf("SendMarkdown failed: %v", err)
 61 | 	}
 62 | }
 63 | 
 64 | // TestSendImage tests the SendImage method.
 65 | func TestSendImage(t *testing.T) {
 66 | 	mockServer := NewMockWeComServer()
 67 | 	defer mockServer.Close()
 68 | 
 69 | 	bot := NewWeComBot(mockServer.URL, "")
 70 | 	err := bot.SendImage("SGVsbG8sIFdlQ29tIQ==", "d41d8cd98f00b204e9800998ecf8427e")
 71 | 	if err != nil {
 72 | 		t.Errorf("SendImage failed: %v", err)
 73 | 	}
 74 | }
 75 | 
 76 | // TestSendNews tests the SendNews method.
 77 | func TestSendNews(t *testing.T) {
 78 | 	mockServer := NewMockWeComServer()
 79 | 	defer mockServer.Close()
 80 | 
 81 | 	bot := NewWeComBot(mockServer.URL, "")
 82 | 	articles := []NewsArticle{
 83 | 		{
 84 | 			Title:       "News Title",
 85 | 			Description: "News Description",
 86 | 			URL:         "https://example.com",
 87 | 			PicURL:      "https://example.com/image.jpg",
 88 | 		},
 89 | 	}
 90 | 	err := bot.SendNews(articles)
 91 | 	if err != nil {
 92 | 		t.Errorf("SendNews failed: %v", err)
 93 | 	}
 94 | }
 95 | 
 96 | // TestSendTemplateCard tests the SendTemplateCard method.
 97 | func TestSendTemplateCard(t *testing.T) {
 98 | 	mockServer := NewMockWeComServer()
 99 | 	defer mockServer.Close()
100 | 
101 | 	bot := NewWeComBot(mockServer.URL, "")
102 | 	err := bot.SendTemplateCard("text_notice", "Main Title", "Main Description", 1, "https://example.com", "", "")
103 | 	if err != nil {
104 | 		t.Errorf("SendTemplateCard failed: %v", err)
105 | 	}
106 | }
107 | 
108 | // TestUploadFile tests the UploadFile method.
109 | func TestUploadFile(t *testing.T) {
110 | 	mockServer := NewMockWeComServer()
111 | 	defer mockServer.Close()
112 | 
113 | 	mockServer.URL = WECOM_BOT_UPLOAD_URL
114 | 	bot := NewWeComBot(mockServer.URL, testkey)
115 | 
116 | 	// Create a temporary file for testing
117 | 	tempFile, err := os.CreateTemp("", "testfile")
118 | 	if err != nil {
119 | 		t.Fatalf("Failed to create temporary file: %v", err)
120 | 	}
121 | 	defer os.Remove(tempFile.Name())
122 | 
123 | 	// Write some content to the temporary file
124 | 	_, err = tempFile.WriteString("Hello, WeCom!")
125 | 	if err != nil {
126 | 		t.Fatalf("Failed to write to temporary file: %v", err)
127 | 	}
128 | 	tempFile.Close()
129 | 
130 | 	mediaID, err := bot.UploadFile(tempFile.Name())
131 | 	if err != nil {
132 | 		t.Errorf("UploadFile failed: %v", err)
133 | 	} else {
134 | 		t.Logf("UploadFile succeeded, media ID: %s", mediaID)
135 | 	}
136 | }
137 | 
```

--------------------------------------------------------------------------------
/wecom.go:
--------------------------------------------------------------------------------

```go
  1 | package main
  2 | 
  3 | import (
  4 | 	"bytes"
  5 | 	"encoding/json"
  6 | 	"fmt"
  7 | 	"io"
  8 | 	"mime/multipart"
  9 | 	"net/http"
 10 | 	"os"
 11 | )
 12 | 
 13 | const (
 14 | 	WECOM_BOT_BASE_URL   = "https://qyapi.weixin.qq.com/cgi-bin/webhook"
 15 | 	WECOM_BOT_SEND_URL   = WECOM_BOT_BASE_URL + "/send?key="
 16 | 	WECOM_BOT_UPLOAD_URL = WECOM_BOT_BASE_URL + "/upload_media?key="
 17 | )
 18 | 
 19 | type WeComBot struct {
 20 | 	WebhookURL string
 21 | 	WebhookKey string
 22 | }
 23 | 
 24 | func NewWeComBot(webhookURL, webhookKey string) *WeComBot {
 25 | 	return &WeComBot{
 26 | 		WebhookURL: webhookURL,
 27 | 		WebhookKey: webhookKey,
 28 | 	}
 29 | }
 30 | 
 31 | // SendText sends a text message to the WeCom group.
 32 | func (bot *WeComBot) SendText(content string, mentionedList []string, mentionedMobileList []string) error {
 33 | 	payload := map[string]interface{}{
 34 | 		"msgtype": "text",
 35 | 		"text": map[string]interface{}{
 36 | 			"content":               content,
 37 | 			"mentioned_list":        mentionedList,
 38 | 			"mentioned_mobile_list": mentionedMobileList,
 39 | 		},
 40 | 	}
 41 | 
 42 | 	return bot.sendRequest(payload)
 43 | }
 44 | 
 45 | // SendMarkdown sends a markdown message to the WeCom group.
 46 | func (bot *WeComBot) SendMarkdown(content string) error {
 47 | 	payload := map[string]interface{}{
 48 | 		"msgtype": "markdown",
 49 | 		"markdown": map[string]interface{}{
 50 | 			"content": content,
 51 | 		},
 52 | 	}
 53 | 
 54 | 	return bot.sendRequest(payload)
 55 | }
 56 | 
 57 | // SendImage sends an image message to the WeCom group.
 58 | func (bot *WeComBot) SendImage(base64Data string, md5 string) error {
 59 | 	payload := map[string]interface{}{
 60 | 		"msgtype": "image",
 61 | 		"image": map[string]interface{}{
 62 | 			"base64": base64Data,
 63 | 			"md5":    md5,
 64 | 		},
 65 | 	}
 66 | 
 67 | 	return bot.sendRequest(payload)
 68 | }
 69 | 
 70 | // SendNews sends a news message to the WeCom group.
 71 | func (bot *WeComBot) SendNews(articles []NewsArticle) error {
 72 | 	payload := map[string]interface{}{
 73 | 		"msgtype": "news",
 74 | 		"news": map[string]interface{}{
 75 | 			"articles": articles,
 76 | 		},
 77 | 	}
 78 | 
 79 | 	return bot.sendRequest(payload)
 80 | }
 81 | 
 82 | // NewsArticle represents a news article in a news message.
 83 | type NewsArticle struct {
 84 | 	Title       string `json:"title"`
 85 | 	Description string `json:"description"`
 86 | 	URL         string `json:"url"`
 87 | 	PicURL      string `json:"picurl"`
 88 | }
 89 | 
 90 | // SendTemplateCard sends a template card message to the WeCom group.
 91 | func (bot *WeComBot) SendTemplateCard(cardType string, mainTitle string, mainDesc string, cardActionType int, cardActionURL string, cardActionAppID string, cardActionPagePath string) error {
 92 | 	payload := map[string]interface{}{
 93 | 		"msgtype": "template_card",
 94 | 		"template_card": map[string]interface{}{
 95 | 			"card_type": cardType,
 96 | 			"main_title": map[string]interface{}{
 97 | 				"title": mainTitle,
 98 | 				"desc":  mainDesc,
 99 | 			},
100 | 			"card_action": map[string]interface{}{
101 | 				"type":     cardActionType,
102 | 				"url":      cardActionURL,
103 | 				"appid":    cardActionAppID,
104 | 				"pagepath": cardActionPagePath,
105 | 			},
106 | 		},
107 | 	}
108 | 
109 | 	return bot.sendRequest(payload)
110 | }
111 | 
112 | // UploadFile uploads a file to WeCom and returns the media ID.
113 | func (bot *WeComBot) UploadFile(filePath string) (string, error) {
114 | 	file, err := os.Open(filePath)
115 | 	if err != nil {
116 | 		return "", err
117 | 	}
118 | 	defer file.Close()
119 | 
120 | 	body := &bytes.Buffer{}
121 | 	writer := multipart.NewWriter(body)
122 | 
123 | 	part, err := writer.CreateFormFile("media", filePath)
124 | 	if err != nil {
125 | 		return "", err
126 | 	}
127 | 
128 | 	_, err = io.Copy(part, file)
129 | 	if err != nil {
130 | 		return "", err
131 | 	}
132 | 
133 | 	err = writer.Close()
134 | 	if err != nil {
135 | 		return "", err
136 | 	}
137 | 
138 | 	resp, err := http.Post(fmt.Sprintf("%s%s&type=file", bot.WebhookURL, bot.WebhookKey), writer.FormDataContentType(), body)
139 | 	if err != nil {
140 | 		return "", err
141 | 	}
142 | 	defer resp.Body.Close()
143 | 
144 | 	var result map[string]interface{}
145 | 	err = json.NewDecoder(resp.Body).Decode(&result)
146 | 	if err != nil {
147 | 		return "", err
148 | 	}
149 | 
150 | 	if result["errcode"].(float64) != 0 {
151 | 		return "", fmt.Errorf("WeCom API error: %s", result["errmsg"].(string))
152 | 	}
153 | 
154 | 	return result["media_id"].(string), nil
155 | }
156 | 
157 | // sendRequest sends a request to the WeCom API with the given payload.
158 | func (bot *WeComBot) sendRequest(payload map[string]interface{}) error {
159 | 	jsonPayload, err := json.Marshal(payload)
160 | 	if err != nil {
161 | 		return err
162 | 	}
163 | 
164 | 	url := bot.WebhookURL + bot.WebhookKey
165 | 	resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonPayload))
166 | 	if err != nil {
167 | 		return err
168 | 	}
169 | 	defer resp.Body.Close()
170 | 
171 | 	var result map[string]interface{}
172 | 	err = json.NewDecoder(resp.Body).Decode(&result)
173 | 	if err != nil {
174 | 		return err
175 | 	}
176 | 
177 | 	if result["errcode"].(float64) != 0 {
178 | 		return fmt.Errorf("WeCom API error: %s", result["errmsg"].(string))
179 | 	}
180 | 
181 | 	return nil
182 | }
183 | 
```

--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------

```go
  1 | package main
  2 | 
  3 | import (
  4 | 	"context"
  5 | 	"fmt"
  6 | 	"log"
  7 | 	"os"
  8 | 	"strings"
  9 | 
 10 | 	"github.com/mark3labs/mcp-go/mcp"
 11 | 	"github.com/mark3labs/mcp-go/server"
 12 | )
 13 | 
 14 | func main() {
 15 | 	webhookKey := os.Getenv("WECOM_BOT_WEBHOOK_KEY")
 16 | 	if webhookKey == "" {
 17 | 		log.Println("WECOM_BOT_WEBHOOK_KEY environment variable is required")
 18 | 		return
 19 | 	}
 20 | 
 21 | 	bot := NewWeComBot(WECOM_BOT_SEND_URL, webhookKey)
 22 | 
 23 | 	s := server.NewMCPServer(
 24 | 		"mcp-wecombot-server",
 25 | 		"1.0.0",
 26 | 		server.WithResourceCapabilities(true, true),
 27 | 		server.WithLogging(),
 28 | 	)
 29 | 
 30 | 	sendTextTool := mcp.NewTool("send_text",
 31 | 		mcp.WithDescription("Send a text message to WeCom group"),
 32 | 		mcp.WithString("content",
 33 | 			mcp.Required(),
 34 | 			mcp.Description("Text content to send"),
 35 | 		),
 36 | 		mcp.WithString("mentioned_list",
 37 | 			mcp.Description("List of user IDs to mention,Multiple people use commas to separate, such as @xiaoyang, @wike."),
 38 | 		),
 39 | 		mcp.WithString("mentioned_mobile_list",
 40 | 			mcp.Description("List of mobile numbers to mention,Multiple people use commas to separate, such as @xiaoyang, @wike."),
 41 | 		),
 42 | 	)
 43 | 	s.AddTool(sendTextTool, sendTextHandler(bot))
 44 | 
 45 | 	sendMarkdownTool := mcp.NewTool("send_markdown",
 46 | 		mcp.WithDescription("Send a markdown message to WeCom group"),
 47 | 		mcp.WithString("content",
 48 | 			mcp.Required(),
 49 | 			mcp.Description("Markdown content to send"),
 50 | 		),
 51 | 	)
 52 | 	s.AddTool(sendMarkdownTool, sendMarkdownHandler(bot))
 53 | 
 54 | 	sendImageTool := mcp.NewTool("send_image",
 55 | 		mcp.WithDescription("Send an image message to WeCom group"),
 56 | 		mcp.WithString("base64_data",
 57 | 			mcp.Required(),
 58 | 			mcp.Description("Base64 encoded image data"),
 59 | 		),
 60 | 		mcp.WithString("md5",
 61 | 			mcp.Required(),
 62 | 			mcp.Description("MD5 hash of the image"),
 63 | 		),
 64 | 	)
 65 | 	s.AddTool(sendImageTool, sendImageHandler(bot))
 66 | 
 67 | 	sendNewsTool := mcp.NewTool("send_news",
 68 | 		mcp.WithDescription("Send a news message to WeCom group"),
 69 | 		mcp.WithString("title", mcp.Required(), mcp.Description("Title of the news article")),
 70 | 		mcp.WithString("description", mcp.Description("Description of the news article")),
 71 | 		mcp.WithString("url", mcp.Required(), mcp.Description("URL of the news article")),
 72 | 		mcp.WithString("picurl", mcp.Description("Picture URL of the news article")),
 73 | 	)
 74 | 	s.AddTool(sendNewsTool, sendNewsHandler(bot))
 75 | 
 76 | 	sendTemplateCardTool := mcp.NewTool("send_template_card",
 77 | 		mcp.WithDescription("Send a template card message to WeCom group"),
 78 | 		mcp.WithString("card_type",
 79 | 			mcp.Required(),
 80 | 			mcp.Description("Type of the template card"),
 81 | 		),
 82 | 		mcp.WithString("main_title",
 83 | 			mcp.Required(),
 84 | 			mcp.Description("Main title of the template card"),
 85 | 		),
 86 | 		mcp.WithString("main_desc",
 87 | 			mcp.Description("Main description of the template card"),
 88 | 		),
 89 | 		mcp.WithNumber("card_action_type",
 90 | 			mcp.Required(),
 91 | 			mcp.Description("Type of the card action"),
 92 | 		),
 93 | 		mcp.WithString("card_action_url",
 94 | 			mcp.Description("URL for the card action"),
 95 | 		),
 96 | 		mcp.WithString("card_action_appid",
 97 | 			mcp.Description("App ID for the card action"),
 98 | 		),
 99 | 		mcp.WithString("card_action_pagepath",
100 | 			mcp.Description("Page path for the card action"),
101 | 		),
102 | 	)
103 | 	s.AddTool(sendTemplateCardTool, sendTemplateCardHandler(bot))
104 | 
105 | 	uploadFileTool := mcp.NewTool("upload_file",
106 | 		mcp.WithDescription("Upload a file to WeCom"),
107 | 		mcp.WithString("file_path",
108 | 			mcp.Required(),
109 | 			mcp.Description("Path to the file to upload"),
110 | 		),
111 | 	)
112 | 	s.AddTool(uploadFileTool, uploadFileHandler(bot))
113 | 
114 | 	if err := server.ServeStdio(s); err != nil {
115 | 		log.Printf("Server error: %v\n", err)
116 | 	}
117 | }
118 | func sendTextHandler(bot *WeComBot) func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
119 | 	return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
120 | 		var mentionedListStr string
121 | 		var mentionedMobileListStr string
122 | 		var mentionedList []string
123 | 		var mentionedMobileList []string
124 | 
125 | 		content := request.Params.Arguments["content"].(string)
126 | 
127 | 		if request.Params.Arguments["mentioned_list"] == nil && request.Params.Arguments["mentioned_mobile_list"] == nil {
128 | 			mentionedListStr = ""
129 | 			mentionedMobileListStr = ""
130 | 		} else {
131 | 			mentionedListStr = request.Params.Arguments["mentioned_list"].(string)
132 | 			mentionedMobileListStr = request.Params.Arguments["mentioned_mobile_list"].(string)
133 | 		}
134 | 
135 | 		if mentionedListStr != "" && mentionedMobileListStr != "" {
136 | 			mentionedList = strings.Split(mentionedListStr, ",")
137 | 			mentionedMobileList = strings.Split(mentionedMobileListStr, ",")
138 | 		} else {
139 | 			mentionedList = []string{}
140 | 			mentionedMobileList = []string{}
141 | 		}
142 | 
143 | 		err := bot.SendText(content, mentionedList, mentionedMobileList)
144 | 		if err != nil {
145 | 			return mcp.NewToolResultError(fmt.Sprintf("Failed to send text message: %v", err)), nil
146 | 		}
147 | 
148 | 		return mcp.NewToolResultText("Text message sent successfully"), nil
149 | 	}
150 | }
151 | 
152 | func sendMarkdownHandler(bot *WeComBot) func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
153 | 	return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
154 | 		content := request.Params.Arguments["content"].(string)
155 | 
156 | 		bot.WebhookURL = WECOM_BOT_SEND_URL
157 | 		err := bot.SendMarkdown(content)
158 | 		if err != nil {
159 | 			return mcp.NewToolResultError(fmt.Sprintf("Failed to send markdown message: %v", err)), nil
160 | 		}
161 | 
162 | 		return mcp.NewToolResultText("Markdown message sent successfully"), nil
163 | 	}
164 | }
165 | 
166 | func sendImageHandler(bot *WeComBot) func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
167 | 	return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
168 | 		base64Data := request.Params.Arguments["base64_data"].(string)
169 | 		md5 := request.Params.Arguments["md5"].(string)
170 | 
171 | 		bot.WebhookURL = WECOM_BOT_SEND_URL
172 | 		err := bot.SendImage(base64Data, md5)
173 | 		if err != nil {
174 | 			return mcp.NewToolResultError(fmt.Sprintf("Failed to send image message: %v", err)), nil
175 | 		}
176 | 
177 | 		return mcp.NewToolResultText("Image message sent successfully"), nil
178 | 	}
179 | }
180 | 
181 | func sendNewsHandler(bot *WeComBot) func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
182 | 	return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
183 | 		// Extract the parameters from the request
184 | 		title := request.Params.Arguments["title"].(string)
185 | 		description := request.Params.Arguments["description"].(string)
186 | 		url := request.Params.Arguments["url"].(string)
187 | 		picurl := request.Params.Arguments["picurl"].(string)
188 | 
189 | 		// Create a single NewsArticle
190 | 		newsArticle := NewsArticle{
191 | 			Title:       title,
192 | 			Description: description,
193 | 			URL:         url,
194 | 			PicURL:      picurl,
195 | 		}
196 | 
197 | 		// Send the news article
198 | 		bot.WebhookURL = WECOM_BOT_SEND_URL
199 | 		err := bot.SendNews([]NewsArticle{newsArticle})
200 | 		if err != nil {
201 | 			return mcp.NewToolResultError(fmt.Sprintf("Failed to send news message: %v", err)), nil
202 | 		}
203 | 
204 | 		// Return success result
205 | 		return mcp.NewToolResultText("News message sent successfully"), nil
206 | 	}
207 | }
208 | 
209 | func sendTemplateCardHandler(bot *WeComBot) func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
210 | 	return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
211 | 		cardType := request.Params.Arguments["card_type"].(string)
212 | 		mainTitle := request.Params.Arguments["main_title"].(string)
213 | 		mainDesc := request.Params.Arguments["main_desc"].(string)
214 | 		cardActionType := request.Params.Arguments["card_action_type"].(int)
215 | 		cardActionURL := request.Params.Arguments["card_action_url"].(string)
216 | 		cardActionAppID := request.Params.Arguments["card_action_appid"].(string)
217 | 		cardActionPagePath := request.Params.Arguments["card_action_pagepath"].(string)
218 | 
219 | 		bot.WebhookURL = WECOM_BOT_SEND_URL
220 | 		err := bot.SendTemplateCard(cardType, mainTitle, mainDesc, cardActionType, cardActionURL, cardActionAppID, cardActionPagePath)
221 | 		if err != nil {
222 | 			return mcp.NewToolResultError(fmt.Sprintf("Failed to send template card message: %v", err)), nil
223 | 		}
224 | 
225 | 		return mcp.NewToolResultText("Template card message sent successfully"), nil
226 | 	}
227 | }
228 | 
229 | func uploadFileHandler(bot *WeComBot) func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
230 | 	return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
231 | 		filePath := request.Params.Arguments["file_path"].(string)
232 | 
233 | 		bot.WebhookURL = WECOM_BOT_UPLOAD_URL
234 | 		mediaID, err := bot.UploadFile(filePath)
235 | 		if err != nil {
236 | 			return mcp.NewToolResultError(fmt.Sprintf("Failed to upload file: %v", err)), nil
237 | 		}
238 | 
239 | 		return mcp.NewToolResultText(fmt.Sprintf("File uploaded successfully, media ID: %s", mediaID)), nil
240 | 	}
241 | }
242 | 
```