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
安全注意事项
- Secret不要硬编码:使用环境变量或Vault
- IP白名单:企业微信后台设置API调用IP白名单
- 消息审计:所有发送的消息记录审计日志
- 频率限制:企业微信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工具都能直接使用。
- MCP Server一次实现,到处使用:Claude、Cursor、自建Agent都能连接
- Spring Boot生态加持:企业微信SDK、权限、审计开箱即用
- 生产级可用:Token自动刷新、限流、审计日志、Docker部署
这是企业级AI Agent落地的最短路径——从"AI能聊天"到"AI能干活",MCP让这一切变得简单。
本站提供浏览器本地工具,免注册即可试用 →
#MCP#企业微信#AI Agent#WeCom#工具调用#企业级