5分钟搭建一个能连接企业微信的AI Agent:MCP协议实战教程

技术架构

为什么选择企业微信 + MCP?

企业微信覆盖了80%以上的国内企业,是企业内部沟通的事实标准。将AI Agent接入企业微信,意味着:

  • 零学习成本:员工在熟悉的聊天界面中就能使用AI
  • 天然权限体系:复用企业微信的组织架构和权限
  • 消息触达:AI可以主动推送消息给员工和群组
  • 审批集成:AI可以代员工发起审批流程

企业微信 + MCP = 企业级AI Agent的最短路径


整体架构

┌──────────────┐     MCP协议      ┌──────────────────┐     HTTP API     ┌──────────────┐
│  AI Agent    │ ◄──────────────► │   MCP Server     │ ◄──────────────► │  企业微信API  │
│  (Claude等)  │   JSON-RPC      │  (我们的实现)     │   REST调用       │  (WeCom)     │
└──────────────┘                  └──────────────────┘                  └──────────────┘

MCP Server暴露的Tools:
├── send_message        发送消息给用户/群
├── search_contacts     搜索通讯录
├── get_department      获取部门信息
├── create_approval     发起审批
├── upload_file         上传文件到企业微信
└── get_chat_history    获取群聊历史

第一步:创建企业微信应用

1.1 获取企业微信凭证

登录企业微信管理后台

1. 应用管理 → 创建应用
2. 记录以下凭证:
   - corpId: ww1234567890abcdef
   - agentId: 1000002
   - secret: xxxxxxxxxxxxxxxxxxxxxxxxxx
3. 设置回调URL: https://your-domain.com/wecom/callback

1.2 配置可信域名

应用详情 → 网页授权及JS-SDK → 设置可信域名
添加: your-domain.com

第二步:实现MCP Server

2.1 项目结构

wecom-mcp-server/
├── src/main/java/com/example/wecom/
│   ├── WecomMcpServerApplication.java
│   ├── config/
│   │   └── WecomConfig.java
│   ├── mcp/
│   │   ├── WecomMcpServer.java
│   │   └── tools/
│   │       ├── SendMessageTool.java
│   │       ├── SearchContactsTool.java
│   │       ├── GetDepartmentTool.java
│   │       └── CreateApprovalTool.java
│   ├── wecom/
│   │   ├── WecomApiClient.java
│   │   └── WecomTokenManager.java
│   └── model/
│       ├── WecomMessage.java
│       └── WecomContact.java
└── pom.xml

2.2 核心依赖

<dependencies>
    <dependency>
        <groupId>io.modelcontextprotocol</groupId>
        <artifactId>mcp-spring-boot-starter</artifactId>
        <version>0.7.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>3.3.0</version>
    </dependency>
    <dependency>
        <groupId>com.dtfly.oa</groupId>
        <artifactId>wecom-sdk</artifactId>
        <version>1.2.0</version>
    </dependency>
</dependencies>

2.3 MCP Server核心实现

@SpringBootApplication
public class WecomMcpServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(WecomMcpServerApplication.class, args);
    }
}

@Configuration
@ConfigurationProperties(prefix = "wecom")
@Data
public class WecomConfig {
    private String corpId;
    private String agentId;
    private String secret;
    private String token;
    private String encodingAesKey;
}
@Component
public class WecomMcpServer {

    private final McpServer mcpServer;
    private final WecomApiClient wecomClient;

    public WecomMcpServer(McpServer.Builder builder,
                          WecomApiClient wecomClient,
                          List<McpTool> tools) {
        this.wecomClient = wecomClient;
        this.mcpServer = builder
            .name("wecom-mcp-server")
            .version("1.0.0")
            .tools(tools)
            .build();
    }

    @PostConstruct
    public void start() {
        mcpServer.start();
    }
}

2.4 发送消息Tool

@Component
public class SendMessageTool implements McpTool {

    private final WecomApiClient wecomClient;

    @Override
    public String name() {
        return "send_message";
    }

    @Override
    public String description() {
        return "通过企业微信发送消息给指定用户或群组";
    }

    @Override
    public JsonNode inputSchema() {
        return objectMapper.readTree("""
            {
              "type": "object",
              "properties": {
                "receiverType": {
                  "type": "string",
                  "enum": ["user", "group"],
                  "description": "接收者类型:user(个人) 或 group(群组)"
                },
                "receiverId": {
                  "type": "string",
                  "description": "接收者ID,用户ID或群聊ID"
                },
                "messageType": {
                  "type": "string",
                  "enum": ["text", "markdown", "file"],
                  "description": "消息类型"
                },
                "content": {
                  "type": "string",
                  "description": "消息内容"
                }
              },
              "required": ["receiverType", "receiverId", "messageType", "content"]
            }
            """);
    }

    @Override
    public McpToolResult execute(Map<String, Object> args) {
        String receiverType = (String) args.get("receiverType");
        String receiverId = (String) args.get("receiverId");
        String messageType = (String) args.get("messageType");
        String content = (String) args.get("content");

        try {
            String msgId = wecomClient.sendMessage(
                receiverType, receiverId, messageType, content
            );
            return McpToolResult.success(
                Map.of("msgId", msgId, "status", "sent")
            );
        } catch (WecomApiException e) {
            return McpToolResult.error("发送失败: " + e.getMessage());
        }
    }
}

2.5 搜索通讯录Tool

@Component
public class SearchContactsTool implements McpTool {

    private final WecomApiClient wecomClient;

    @Override
    public String name() {
        return "search_contacts";
    }

    @Override
    public String description() {
        return "在企业微信通讯录中搜索联系人";
    }

    @Override
    public JsonNode inputSchema() {
        return objectMapper.readTree("""
            {
              "type": "object",
              "properties": {
                "keyword": {
                  "type": "string",
                  "description": "搜索关键词(姓名、部门等)"
                },
                "departmentId": {
                  "type": "integer",
                  "description": "限定部门ID(可选)"
                },
                "limit": {
                  "type": "integer",
                  "description": "返回数量限制",
                  "default": 20
                }
              },
              "required": ["keyword"]
            }
            """);
    }

    @Override
    public McpToolResult execute(Map<String, Object> args) {
        String keyword = (String) args.get("keyword");
        Integer limit = (Integer) args.getOrDefault("limit", 20);

        List<WecomContact> contacts = wecomClient.searchContacts(keyword, limit);

        return McpToolResult.success(Map.of(
            "contacts", contacts,
            "total", contacts.size()
        ));
    }
}

2.6 企业微信API客户端

@Component
public class WecomApiClient {

    private final RestTemplate restTemplate;
    private final WecomConfig config;
    private final WecomTokenManager tokenManager;

    public String sendMessage(String receiverType, String receiverId,
                              String messageType, String content) {
        String accessToken = tokenManager.getAccessToken();

        Map<String, Object> body = new HashMap<>();
        body.put("msgtype", messageType);
        body.put("agentid", config.getAgentId());

        if ("user".equals(receiverType)) {
            body.put("touser", receiverId);
        } else {
            body.put("chatid", receiverId);
        }

        Map<String, String> msgContent = Map.of("content", content);
        body.put(messageType, msgContent);

        ResponseEntity<String> response = restTemplate.postForEntity(
            "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + accessToken,
            body,
            String.class
        );

        JsonNode json = objectMapper.readTree(response.getBody());
        return json.path("msgid").asText();
    }

    public List<WecomContact> searchContacts(String keyword, int limit) {
        String accessToken = tokenManager.getAccessToken();
        // 调用企业微信通讯录搜索API
        // ...
    }
}

2.7 Token管理(自动刷新)

@Component
public class WecomTokenManager {

    private final WecomConfig config;
    private final RestTemplate restTemplate;
    private String accessToken;
    private long expiresAt;

    public synchronized String getAccessToken() {
        if (accessToken != null && System.currentTimeMillis() < expiresAt) {
            return accessToken;
        }
        refreshAccessToken();
        return accessToken;
    }

    private void refreshAccessToken() {
        String url = String.format(
            "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s",
            config.getCorpId(), config.getSecret()
        );

        JsonNode json = restTemplate.getForObject(url, JsonNode.class);
        this.accessToken = json.path("access_token").asText();
        int expiresIn = json.path("expires_in").asInt();
        this.expiresAt = System.currentTimeMillis() + (expiresIn - 300) * 1000L;
    }
}

第三步:配置与启动

application.yml

server:
  port: 8081

wecom:
  corpId: ${WECOM_CORP_ID}
  agentId: ${WECOM_AGENT_ID}
  secret: ${WECOM_SECRET}
  token: ${WECOM_CALLBACK_TOKEN}
  encodingAesKey: ${WECOM_ENCODING_AES_KEY}

mcp:
  server:
    name: wecom-mcp-server
    version: 1.0.0
    transport: sse
    sseEndpoint: /mcp/sse

启动与测试

# 设置环境变量
export WECOM_CORP_ID=ww1234567890abcdef
export WECOM_AGENT_ID=1000002
export WECOM_SECRET=your_secret_here

# 启动MCP Server
mvn spring-boot:run

# 测试MCP连接
curl http://localhost:8081/mcp/sse

第四步:在Claude Desktop中配置

编辑 claude_desktop_config.json

{
  "mcpServers": {
    "wecom": {
      "url": "http://localhost:8081/mcp/sse",
      "transport": "sse"
    }
  }
}

现在你可以在Claude中直接使用企业微信功能了:

用户:帮我给产品组的群发一条消息,通知明天下午3点有评审会议

Claude:我来帮你发送消息。
[调用 send_message tool]
→ receiverType: "group"
→ receiverId: "产品组群聊ID"
→ messageType: "text"
→ content: "通知:明天下午3点有评审会议,请相关人员准时参加。"

消息已发送成功!msgId: msg_20260611_001

生产级部署

Docker部署

FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY target/wecom-mcp-server.jar app.jar
EXPOSE 8081
ENTRYPOINT ["java", "-jar", "app.jar"]
# docker-compose.yml
version: '3.8'
services:
  wecom-mcp:
    build: .
    ports:
      - "8081:8081"
    environment:
      - WECOM_CORP_ID=${WECOM_CORP_ID}
      - WECOM_AGENT_ID=${WECOM_AGENT_ID}
      - WECOM_SECRET=${WECOM_SECRET}
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8081/mcp/sse"]
      interval: 30s
      timeout: 10s

安全注意事项

  1. Secret不要硬编码:使用环境变量或Vault
  2. IP白名单:企业微信后台设置API调用IP白名单
  3. 消息审计:所有发送的消息记录审计日志
  4. 频率限制:企业微信API有调用频率限制,需要做限流
@Component
public class RateLimitInterceptor implements HandlerInterceptor {

    private final RateLimiter rateLimiter = RateLimiter.create(100); // 100 QPS

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) {
        if (!rateLimiter.tryAcquire()) {
            response.setStatus(429);
            return false;
        }
        return true;
    }
}

扩展:更多企业微信Tool

Tool 功能 企业微信API
get_approval 获取审批详情 审批API
create_approval 发起审批 审批API
upload_file 上传临时素材 素材API
get_external_contact 获取外部联系人 外部联系人API
send_template_card 发送模板卡片消息 消息API
create_calendar 创建日程 日历API

总结

5分钟搭建的核心在于MCP协议的标准化——我们不需要为每个AI应用单独写企业微信集成代码,只需要实现一次MCP Server,所有支持MCP的AI工具都能直接使用。

  1. MCP Server一次实现,到处使用:Claude、Cursor、自建Agent都能连接
  2. Spring Boot生态加持:企业微信SDK、权限、审计开箱即用
  3. 生产级可用:Token自动刷新、限流、审计日志、Docker部署

这是企业级AI Agent落地的最短路径——从"AI能聊天"到"AI能干活",MCP让这一切变得简单。

本站提供浏览器本地工具,免注册即可试用 →

#MCP#企业微信#AI Agent#WeCom#工具调用#企业级