mirror of
https://github.com/samanhappy/mcphub.git
synced 2025-12-24 02:39:19 -05:00
616 lines
12 KiB
Plaintext
616 lines
12 KiB
Plaintext
---
|
||
title: WebHooks API
|
||
description: 配置和管理 WebHook 事件通知的完整指南
|
||
---
|
||
|
||
# WebHooks API
|
||
|
||
WebHooks 允许 MCPHub 在特定事件发生时向您的应用程序发送实时通知。
|
||
|
||
## 概述
|
||
|
||
MCPHub WebHooks 系统支持以下功能:
|
||
|
||
- 实时事件通知
|
||
- 自定义过滤器
|
||
- 重试机制
|
||
- 签名验证
|
||
- 批量事件处理
|
||
|
||
## 支持的事件类型
|
||
|
||
| 事件类型 | 描述 |
|
||
| ----------------------- | -------------- |
|
||
| `server.created` | MCP 服务器创建 |
|
||
| `server.updated` | MCP 服务器更新 |
|
||
| `server.deleted` | MCP 服务器删除 |
|
||
| `server.status_changed` | 服务器状态变更 |
|
||
| `group.created` | 服务器组创建 |
|
||
| `group.updated` | 服务器组更新 |
|
||
| `group.deleted` | 服务器组删除 |
|
||
| `user.login` | 用户登录 |
|
||
| `user.logout` | 用户登出 |
|
||
| `config.changed` | 配置变更 |
|
||
| `system.error` | 系统错误 |
|
||
|
||
## 创建 WebHook
|
||
|
||
### 端点
|
||
|
||
```http
|
||
POST /api/webhooks
|
||
```
|
||
|
||
### 请求体
|
||
|
||
```json
|
||
{
|
||
"url": "https://your-app.com/webhook",
|
||
"events": ["server.created", "server.status_changed"],
|
||
"secret": "your-webhook-secret",
|
||
"active": true,
|
||
"config": {
|
||
"contentType": "application/json",
|
||
"insecureSsl": false,
|
||
"retryCount": 3,
|
||
"timeout": 30
|
||
},
|
||
"filters": {
|
||
"serverGroups": ["production", "staging"],
|
||
"serverTypes": ["ai-assistant", "data-processor"]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 响应
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"id": "webhook-123",
|
||
"url": "https://your-app.com/webhook",
|
||
"events": ["server.created", "server.status_changed"],
|
||
"active": true,
|
||
"secret": "your-webhook-secret",
|
||
"config": {
|
||
"contentType": "application/json",
|
||
"insecureSsl": false,
|
||
"retryCount": 3,
|
||
"timeout": 30
|
||
},
|
||
"filters": {
|
||
"serverGroups": ["production", "staging"],
|
||
"serverTypes": ["ai-assistant", "data-processor"]
|
||
},
|
||
"createdAt": "2024-01-15T10:30:00Z",
|
||
"updatedAt": "2024-01-15T10:30:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 获取 WebHook 列表
|
||
|
||
### 端点
|
||
|
||
```http
|
||
GET /api/webhooks
|
||
```
|
||
|
||
### 查询参数
|
||
|
||
| 参数名 | 类型 | 描述 |
|
||
| ------ | ------- | -------------------- |
|
||
| page | integer | 页码(默认:1) |
|
||
| limit | integer | 每页数量(默认:20) |
|
||
| active | boolean | 过滤活跃状态 |
|
||
| event | string | 过滤事件类型 |
|
||
|
||
### 请求示例
|
||
|
||
```bash
|
||
curl -X GET \
|
||
'https://api.mcphub.io/api/webhooks?active=true&limit=10' \
|
||
-H 'Authorization: Bearer YOUR_API_TOKEN'
|
||
```
|
||
|
||
### 响应
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"webhooks": [
|
||
{
|
||
"id": "webhook-123",
|
||
"url": "https://your-app.com/webhook",
|
||
"events": ["server.created", "server.status_changed"],
|
||
"active": true,
|
||
"lastDelivery": "2024-01-15T09:30:00Z",
|
||
"deliveryCount": 145,
|
||
"failureCount": 2,
|
||
"createdAt": "2024-01-10T10:30:00Z"
|
||
}
|
||
],
|
||
"pagination": {
|
||
"page": 1,
|
||
"limit": 10,
|
||
"total": 25,
|
||
"pages": 3
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 获取单个 WebHook
|
||
|
||
### 端点
|
||
|
||
```http
|
||
GET /api/webhooks/{id}
|
||
```
|
||
|
||
### 响应
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"id": "webhook-123",
|
||
"url": "https://your-app.com/webhook",
|
||
"events": ["server.created", "server.status_changed"],
|
||
"active": true,
|
||
"secret": "your-webhook-secret",
|
||
"config": {
|
||
"contentType": "application/json",
|
||
"insecureSsl": false,
|
||
"retryCount": 3,
|
||
"timeout": 30
|
||
},
|
||
"filters": {
|
||
"serverGroups": ["production", "staging"],
|
||
"serverTypes": ["ai-assistant", "data-processor"]
|
||
},
|
||
"stats": {
|
||
"totalDeliveries": 145,
|
||
"successfulDeliveries": 143,
|
||
"failedDeliveries": 2,
|
||
"lastDelivery": "2024-01-15T09:30:00Z",
|
||
"lastSuccess": "2024-01-15T09:30:00Z",
|
||
"lastFailure": "2024-01-14T15:20:00Z"
|
||
},
|
||
"createdAt": "2024-01-10T10:30:00Z",
|
||
"updatedAt": "2024-01-15T10:30:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 更新 WebHook
|
||
|
||
### 端点
|
||
|
||
```http
|
||
PUT /api/webhooks/{id}
|
||
```
|
||
|
||
### 请求体
|
||
|
||
```json
|
||
{
|
||
"url": "https://your-app.com/new-webhook",
|
||
"events": ["server.created", "server.updated", "server.deleted"],
|
||
"active": true,
|
||
"config": {
|
||
"retryCount": 5,
|
||
"timeout": 45
|
||
}
|
||
}
|
||
```
|
||
|
||
## 删除 WebHook
|
||
|
||
### 端点
|
||
|
||
```http
|
||
DELETE /api/webhooks/{id}
|
||
```
|
||
|
||
### 响应
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "WebHook 已成功删除"
|
||
}
|
||
```
|
||
|
||
## WebHook 事件格式
|
||
|
||
### 基本结构
|
||
|
||
所有 WebHook 事件都遵循以下基本结构:
|
||
|
||
```json
|
||
{
|
||
"id": "event-123",
|
||
"type": "server.created",
|
||
"timestamp": "2024-01-15T10:30:00Z",
|
||
"version": "1.0",
|
||
"data": {
|
||
// 事件特定数据
|
||
},
|
||
"metadata": {
|
||
"source": "mcphub",
|
||
"environment": "production",
|
||
"triggeredBy": "user-456"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 服务器事件示例
|
||
|
||
#### server.created
|
||
|
||
```json
|
||
{
|
||
"id": "event-123",
|
||
"type": "server.created",
|
||
"timestamp": "2024-01-15T10:30:00Z",
|
||
"version": "1.0",
|
||
"data": {
|
||
"server": {
|
||
"id": "mcp-server-123",
|
||
"name": "AI Assistant Server",
|
||
"type": "ai-assistant",
|
||
"endpoint": "https://ai-assistant.example.com",
|
||
"group": "production",
|
||
"status": "active",
|
||
"capabilities": ["chat", "completion"],
|
||
"createdAt": "2024-01-15T10:30:00Z"
|
||
}
|
||
},
|
||
"metadata": {
|
||
"source": "mcphub",
|
||
"environment": "production",
|
||
"triggeredBy": "user-456"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### server.status_changed
|
||
|
||
```json
|
||
{
|
||
"id": "event-124",
|
||
"type": "server.status_changed",
|
||
"timestamp": "2024-01-15T11:30:00Z",
|
||
"version": "1.0",
|
||
"data": {
|
||
"server": {
|
||
"id": "mcp-server-123",
|
||
"name": "AI Assistant Server",
|
||
"previousStatus": "active",
|
||
"currentStatus": "inactive",
|
||
"reason": "Health check failed",
|
||
"lastHealthCheck": "2024-01-15T11:25:00Z"
|
||
}
|
||
},
|
||
"metadata": {
|
||
"source": "mcphub",
|
||
"environment": "production",
|
||
"triggeredBy": "system"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 签名验证
|
||
|
||
MCPHub 使用 HMAC-SHA256 签名来验证 WebHook 的真实性。
|
||
|
||
### 签名生成
|
||
|
||
签名在 `X-MCPHub-Signature-256` 头中发送:
|
||
|
||
```
|
||
X-MCPHub-Signature-256: sha256=5757107ea39eca8e35d1e8...
|
||
```
|
||
|
||
### 验证示例
|
||
|
||
#### Node.js
|
||
|
||
```javascript
|
||
const crypto = require('crypto');
|
||
|
||
function verifySignature(payload, signature, secret) {
|
||
const expectedSignature = crypto
|
||
.createHmac('sha256', secret)
|
||
.update(payload, 'utf8')
|
||
.digest('hex');
|
||
|
||
const actualSignature = signature.replace('sha256=', '');
|
||
|
||
return crypto.timingSafeEqual(
|
||
Buffer.from(expectedSignature, 'hex'),
|
||
Buffer.from(actualSignature, 'hex'),
|
||
);
|
||
}
|
||
|
||
// Express.js 中间件示例
|
||
app.use('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
|
||
const signature = req.headers['x-mcphub-signature-256'];
|
||
const payload = req.body;
|
||
|
||
if (!verifySignature(payload, signature, process.env.WEBHOOK_SECRET)) {
|
||
return res.status(401).send('Unauthorized');
|
||
}
|
||
|
||
// 处理 WebHook 事件
|
||
const event = JSON.parse(payload);
|
||
console.log('收到事件:', event.type);
|
||
|
||
res.status(200).send('OK');
|
||
});
|
||
```
|
||
|
||
#### Python
|
||
|
||
```python
|
||
import hmac
|
||
import hashlib
|
||
|
||
def verify_signature(payload, signature, secret):
|
||
expected_signature = hmac.new(
|
||
secret.encode('utf-8'),
|
||
payload,
|
||
hashlib.sha256
|
||
).hexdigest()
|
||
|
||
actual_signature = signature.replace('sha256=', '')
|
||
|
||
return hmac.compare_digest(expected_signature, actual_signature)
|
||
|
||
# Flask 示例
|
||
from flask import Flask, request, jsonify
|
||
import json
|
||
|
||
app = Flask(__name__)
|
||
|
||
@app.route('/webhook', methods=['POST'])
|
||
def webhook():
|
||
signature = request.headers.get('X-MCPHub-Signature-256')
|
||
payload = request.get_data()
|
||
|
||
if not verify_signature(payload, signature, 'your-webhook-secret'):
|
||
return jsonify({'error': 'Unauthorized'}), 401
|
||
|
||
event = json.loads(payload)
|
||
print(f'收到事件: {event["type"]}')
|
||
|
||
return jsonify({'status': 'success'}), 200
|
||
```
|
||
|
||
## 重试机制
|
||
|
||
MCPHub 对失败的 WebHook 交付实施指数退避重试:
|
||
|
||
- **重试次数**: 可配置(默认 3 次)
|
||
- **重试间隔**: 2^n 秒(n 为重试次数)
|
||
- **最大间隔**: 300 秒(5 分钟)
|
||
- **超时设置**: 可配置(默认 30 秒)
|
||
|
||
### 重试时间表
|
||
|
||
| 尝试次数 | 延迟时间 |
|
||
| -------- | -------- |
|
||
| 1 | 立即 |
|
||
| 2 | 2 秒 |
|
||
| 3 | 4 秒 |
|
||
| 4 | 8 秒 |
|
||
| 5 | 16 秒 |
|
||
|
||
## 获取交付历史
|
||
|
||
### 端点
|
||
|
||
```http
|
||
GET /api/webhooks/{id}/deliveries
|
||
```
|
||
|
||
### 查询参数
|
||
|
||
| 参数名 | 类型 | 描述 |
|
||
| ---------- | ------- | ------------------------------------ |
|
||
| page | integer | 页码 |
|
||
| limit | integer | 每页数量 |
|
||
| status | string | 过滤状态(success, failed, pending) |
|
||
| event_type | string | 过滤事件类型 |
|
||
|
||
### 响应
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"deliveries": [
|
||
{
|
||
"id": "delivery-123",
|
||
"eventId": "event-123",
|
||
"eventType": "server.created",
|
||
"url": "https://your-app.com/webhook",
|
||
"status": "success",
|
||
"responseCode": 200,
|
||
"responseTime": 145,
|
||
"attempts": 1,
|
||
"deliveredAt": "2024-01-15T10:30:15Z",
|
||
"nextRetry": null
|
||
},
|
||
{
|
||
"id": "delivery-124",
|
||
"eventId": "event-124",
|
||
"eventType": "server.status_changed",
|
||
"url": "https://your-app.com/webhook",
|
||
"status": "failed",
|
||
"responseCode": 500,
|
||
"responseTime": 30000,
|
||
"attempts": 3,
|
||
"error": "Connection timeout",
|
||
"deliveredAt": null,
|
||
"nextRetry": "2024-01-15T11:45:00Z"
|
||
}
|
||
],
|
||
"pagination": {
|
||
"page": 1,
|
||
"limit": 20,
|
||
"total": 145,
|
||
"pages": 8
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 测试 WebHook
|
||
|
||
### 端点
|
||
|
||
```http
|
||
POST /api/webhooks/{id}/test
|
||
```
|
||
|
||
### 请求体
|
||
|
||
```json
|
||
{
|
||
"eventType": "server.created",
|
||
"customData": {
|
||
"test": true,
|
||
"message": "这是一个测试事件"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 响应
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"deliveryId": "delivery-test-123",
|
||
"status": "delivered",
|
||
"responseCode": 200,
|
||
"responseTime": 124,
|
||
"sentAt": "2024-01-15T10:30:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 最佳实践
|
||
|
||
### 1. 幂等性处理
|
||
|
||
确保您的 WebHook 端点能够处理重复事件:
|
||
|
||
```javascript
|
||
const processedEvents = new Set();
|
||
|
||
app.post('/webhook', (req, res) => {
|
||
const event = req.body;
|
||
|
||
// 检查事件是否已处理
|
||
if (processedEvents.has(event.id)) {
|
||
return res.status(200).send('Already processed');
|
||
}
|
||
|
||
// 处理事件
|
||
processEvent(event);
|
||
|
||
// 记录已处理的事件
|
||
processedEvents.add(event.id);
|
||
|
||
res.status(200).send('OK');
|
||
});
|
||
```
|
||
|
||
### 2. 异步处理
|
||
|
||
对于复杂的处理逻辑,使用异步处理避免阻塞:
|
||
|
||
```javascript
|
||
app.post('/webhook', async (req, res) => {
|
||
const event = req.body;
|
||
|
||
// 立即响应
|
||
res.status(200).send('OK');
|
||
|
||
// 异步处理事件
|
||
setImmediate(() => {
|
||
processEventAsync(event);
|
||
});
|
||
});
|
||
```
|
||
|
||
### 3. 错误处理
|
||
|
||
实施适当的错误处理和日志记录:
|
||
|
||
```javascript
|
||
app.post('/webhook', (req, res) => {
|
||
try {
|
||
const event = req.body;
|
||
processEvent(event);
|
||
res.status(200).send('OK');
|
||
} catch (error) {
|
||
console.error('WebHook 处理错误:', error);
|
||
res.status(500).send('Internal Server Error');
|
||
}
|
||
});
|
||
```
|
||
|
||
### 4. 监控和告警
|
||
|
||
监控 WebHook 的交付状态:
|
||
|
||
```bash
|
||
# 检查失败的交付
|
||
curl -X GET \
|
||
'https://api.mcphub.io/api/webhooks/webhook-123/deliveries?status=failed' \
|
||
-H 'Authorization: Bearer YOUR_API_TOKEN'
|
||
```
|
||
|
||
## 故障排除
|
||
|
||
### 常见问题
|
||
|
||
1. **签名验证失败**
|
||
|
||
- 检查密钥是否正确
|
||
- 确保使用原始请求体进行验证
|
||
- 验证 HMAC 计算实现
|
||
|
||
2. **超时错误**
|
||
|
||
- 增加 WebHook 超时设置
|
||
- 优化端点响应时间
|
||
- 使用异步处理
|
||
|
||
3. **重复事件**
|
||
- 实施幂等性检查
|
||
- 使用事件 ID 去重
|
||
- 记录处理状态
|
||
|
||
### 调试工具
|
||
|
||
使用 MCPHub 提供的调试工具:
|
||
|
||
```bash
|
||
# 查看最近的交付日志
|
||
curl -X GET \
|
||
'https://api.mcphub.io/api/webhooks/webhook-123/deliveries?limit=5' \
|
||
-H 'Authorization: Bearer YOUR_API_TOKEN'
|
||
|
||
# 重新发送失败的事件
|
||
curl -X POST \
|
||
'https://api.mcphub.io/api/webhooks/delivery-124/redeliver' \
|
||
-H 'Authorization: Bearer YOUR_API_TOKEN'
|
||
```
|