转录Webhook MCP服务器
一个MCP服务器,用于管理团队会议记录的Microsoft Graph webhook订阅并记录更改通知。用途 应用层 (客户端凭据)身份验证。
伴侣: 转录MCP服务器 (委托OBO认证)——按需转录检索服务器。
______________________________________________________________________
建筑
┌─────────────────────────────────────────┐
│ Transcripts Webhook MCP Server │
│ Auth: Application (Client Credentials) │
│ │
│ POST /mcp ─────── MCP Protocol │
│ Tools (8): │
│ • subscribe_to_transcripts │
│ • subscribe_to_recordings │
│ • list_subscriptions │
│ • renew_subscription │
│ • delete_subscription │
│ • get_notification_log │
│ • get_transcript_content │
│ • get_recording_url │
│ │
│ Resources (5): │
│ • webhook://status │
│ • webhook://subscriptions/{id} │
│ • webhook://notifications/{index} │
│ • webhook://transcripts/{u}/{m}/{t} │
│ • webhook://recordings/{u}/{m}/{r} │
│ │
│ POST /notifications ─── Graph Webhook │
│ • Validation handshake │
│ • Notification processing │
│ • Lifecycle event handling │
│ │
│ GET /health ────── Health Check │
└─────────────────┬───────────────────────┘
│
┌───────────┴──────────┐
▼ ▼
┌──────────┐ ┌──────────────┐
│ Graph │ │ Agent / │
│ Webhooks│ │ Copilot │
│ (push) │ │ (pull MCP) │
└──────────┘ └──────────────┘授权与应用程序授权
||转录MCP服务器|此Webhook服务器| |--|------------------------|---------------------| | 认证流程 |委托OBO(用户在场)|仅应用程序客户端凭据| | 身份 |充当登录用户|充当应用程序| | 范围 |仅限用户会议|所有用户会议| | 用例 |按需检索|事件驱动自动化| | 扩展 |缩放到0(按需)|始终打开(webhook侦听器)|
______________________________________________________________________
工具
| 工具 | 说明 |
|---|---|
subscribe_to_transcripts | 为所有用户的新转录事件创建webhook订阅 |
subscribe_to_recordings | 为所有用户的新录制事件创建webhook订阅 |
list_subscriptions | 列出所有活动的webhook订阅(本地+可选Graph API检查) |
renew_subscription | 在订阅到期之前延长订阅期限(最长约70小时) |
delete_subscription | 删除webhook订阅 |
get_notification_log | 查看最近收到的通知和处理结果 |
get_transcript_content | 使用用户ID、会议ID和转录ID从通知日志中获取特定会议的完整转录(VTT格式) |
get_recording_url | 使用通知日志中的userId、meetingId和recordingId获取特定会议录制的限时下载URL |
______________________________________________________________________
资源
MCP资源提供了结构化的、URI可寻址的数据,代理可以直接读取这些数据,从而补充了上述工具。
| 资源 | URI | 描述 |
|---|---|---|
| 服务器状态 | webhook://status | 带有健康状况、活动订阅、通知统计和配置的实时仪表板 |
| 订阅详细信息 | webhook://subscriptions/{subscriptionId} | 特定跟踪订阅的详细信息(到期、通知URL、剩余时间) |
| 通知条目 | webhook://notifications/{index} | 按索引(0=最新)显示的特定通知,包含所有字段,包括成绩单内容 |
| 成绩单内容 | webhook://transcripts/{userId}/{meetingId}/{transcriptId} | 从Microsoft Graph实时获取完整的VTT成绩单 |
| 录制URL | webhook://recordings/{userId}/{meetingId}/{recordingId} | 从Microsoft Graph实时获取的限时下载URL |
注: 资源模板通过以下方式列出 resources/templates/list 并支持自动完成通知日志中的变量。______________________________________________________________________
场景和用例
1.自动会议记录
AI代理监控整个组织的所有团队会议。创建成绩单时,它会自动获取内容,生成包含操作项的摘要,并将其发布到Teams频道或SharePoint网站。
Meeting ends → Graph notification → auto-fetch transcript → agent summarises → posts to channel使用的工具: subscribe_to_transcripts → get_notification_log → get_transcript_content
2.合规与记录保存
合规团队需要对所有记录的会议进行审计跟踪。webhook服务器实时捕获每个记录事件,代理定期检查日志并将记录URL存档到合规系统。
Recording created → Graph notification → agent retrieves download URL → archives to compliance store使用的工具: subscribe_to_recordings → get_notification_log → get_recording_url
3.实时会议智能仪表板
连接到此MCP服务器的Copilot Studio代理为管理人员提供了一个对话界面,可以提出以下问题:
- *“今天有会议记录吗?”*
- *“给我看上次项目脱口秀的记录”*
- *“本周收到了多少份成绩单通知?”*
使用的工具: get_notification_log → get_transcript_content
4.会议情绪与主题分析
每次会议后,代理都会获取记录并运行情绪分析或主题提取。结果存储在数据库中用于趋势跟踪,例如跟踪团队士气在冲刺周期中的变化。
Transcript notification → fetch VTT content → parse speakers & dialogue → analyse sentiment → store trends使用的工具: subscribe_to_transcripts → get_transcript_content
5.自动跟进电子邮件
代理人观察新的记录,总结讨论,提取行动项目和所有者,然后起草后续电子邮件给会议参与者。
Transcript created → fetch content → extract action items → draft & send follow-up email使用的工具: get_notification_log → get_transcript_content
6.多租户监控
MSP或IT团队部署具有应用程序级权限的此服务器,以监控整个租户的会议活动,无需单个用户登录。始终在线的webhook侦听器确保即使在工作时间之外也不会错过任何事件。
主要优势:应用程序身份验证意味着服务器独立于任何用户会话运行。
7.培训和知识库
自动捕获培训课程、入职电话或客户演示的会议记录。代理获取成绩单,清理VTT格式,并将其作为可搜索文档存储在知识库中。
Training meeting ends → transcript notification → fetch content → clean & index → add to knowledge base使用的工具: subscribe_to_transcripts → get_transcript_content
8.订阅健康监测
代理会定期检查订阅状态,并在订阅到期前自动续订(最大生存期约为70小时)。如果Graph删除了订阅,代理将检测生命周期事件并重新创建。
Agent on schedule → list_subscriptions (with Graph check) → renew if **重要**:这些是 **应用** 权限(未委派)。他们要求 **管理员同意**.
### 管理员同意
az ad app permission admin-consent --id
### 客户端密钥
1. 首选 **证书和秘密** → **新客户机密**
1. 复制机密值(您将不会再看到它)
1. 设置为 `AZURE_CLIENT_SECRET` 环境变量
______________________________________________________________________
## 环境变量
|变量|必填|描述|
|----------|----------|-------------|
| `AZURE_CLIENT_ID` |是|应用程序注册中的应用程序(客户端)ID|
| `AZURE_CLIENT_SECRET` |是|客户端机密值|
| `AZURE_TENANT_ID` |是|目录(租户)ID|
| `NOTIFICATION_URL` |推荐|用于webhook通知的公共HTTPS URL(例如。 `https://your-app.azurecontainerapps.io/notifications`) |
| `PORT` |无|服务器端口(默认:8080)|
______________________________________________________________________
## 部署
### 码头工人
docker build -t transcripts-webhook-mcp . docker run -p 8080:8080 \ -e AZURE_CLIENT_ID=your-client-id \ -e AZURE_CLIENT_SECRET=your-secret \ -e AZURE_TENANT_ID=your-tenant-id \ -e NOTIFICATION_URL=https://your-app.example.com/notifications \ transcripts-webhook-mcp
### Azure容器应用
Create ACR and build
az acr create -n -g --sku Basic --admin-enabled az acr build -r -t transcripts-webhook-mcp:v1 .
Create always-on container app (min replicas = 1)
az containerapp create \ --name transcripts-webhook-mcp \ --resource-group \ --image .azurecr.io/transcripts-webhook-mcp:v1 \ --target-port 8080 \ --ingress external \ --min-replicas 1 \ --max-replicas 2 \ --env-vars \ AZURE_CLIENT_ID= \ AZURE_CLIENT_SECRET=secretref:client-secret \ AZURE_TENANT_ID= \ NOTIFICATION_URL=https:///notifications
> **备注**: `--min-replicas 1` --此服务器必须保持运行才能接收webhook通知。与可以扩展到0的委托MCP服务器不同。
______________________________________________________________________
## Webhooks的工作原理
- Agent calls subscribe_to_transcripts
│ ▼
- Server POSTs to Graph /subscriptions
│ ▼
- Graph POSTs to /notifications?validationToken=xxx
│ ▼
- Server echoes validationToken → subscription confirmed
│ ▼
- User creates a meeting transcript in Teams
│ ▼
- Graph POSTs notification to /notifications
{ "subscriptionId": "...", "changeType": "created", "resource": "users/{userId}/onlineMeetings/{meetingId}/transcripts/{id}", "tenantId": "..." } │ ▼
- Server logs notification, extracts user/meeting/transcript IDs
- Server auto-fetches transcript content (VTT) or recording URL
- Agent can retrieve content on-demand via get_transcript_content / get_recording_url
### 订阅生命周期
- **最大寿命**:约4230分钟(约70.5小时)用于在线会议资源
- **续订**:必须致电 `renew_subscription` 到期前
- **生命周期事件**:图形发送 `reauthorizationRequired`, `subscriptionRemoved`, `missed` 通知
______________________________________________________________________
## 本地开发
npm install npm run build npm start
对于本地测试,通知URL必须可公开访问。使用类似隧道的 [吸烟](https://ngrok.com/) 或 [Azure开发隧道](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/):
Using dev tunnels
devtunnel create --allow-anonymous devtunnel port create -p 8080 devtunnel host
Use the tunnel URL as NOTIFICATION_URL
______________________________________________________________________
## 测试
### 健康检查
curl http://localhost:8080/health
### MCP工具(通过curl)
所有工具均通过调用 `POST /mcp` 使用具有SSE响应格式的JSON-RPC 2.0。
#### 订阅成绩单
为所有用户创建用于成绩单更改通知的webhook订阅。
With defaults (uses server's NOTIFICATION_URL, 4200 min expiry)
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"subscribe_to_transcripts","arguments":{}}}'
With custom options
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"subscribe_to_transcripts","arguments":{"notificationUrl":"https://your-app.example.com/notifications","expirationMinutes":4230,"clientState":"my-secret-state"}}}'
#### 订阅录音
创建一个webhook订阅,用于记录所有用户的更改通知。
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"subscribe_to_recordings","arguments":{}}}'
#### 列出订阅
列出所有活动的webhook订阅。根据Graph API进行可选验证。
Local state only (fast)
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_subscriptions","arguments":{}}}'
With Graph API verification (slower but more accurate)
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_subscriptions","arguments":{"includeGraphCheck":true}}}'
#### 续订订阅
延长订阅的到期时间。必须在订阅失效前调用(最大生存期约为70小时)。
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"renew_subscription","arguments":{"subscriptionId":"YOUR-SUBSCRIPTION-ID"}}}'
With custom expiry
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"renew_subscription","arguments":{"subscriptionId":"YOUR-SUBSCRIPTION-ID","expirationMinutes":4230}}}'
#### 删除订阅
删除webhook订阅,停止所有未来的通知。
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"delete_subscription","arguments":{"subscriptionId":"YOUR-SUBSCRIPTION-ID"}}}'
#### 获取通知日志
查看服务器最近收到的webhook通知。
Default (last 20 notifications)
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_notification_log","arguments":{}}}'
Last 5 notifications
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_notification_log","arguments":{"limit":5}}}'
#### 获取成绩单内容
获取特定会议的完整成绩单(VTT格式)。使用通知日志中的userId、meetingId和transcriptId。
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_transcript_content","arguments":{"userId":"USER-ID-FROM-LOG","meetingId":"MEETING-ID-FROM-LOG","transcriptId":"TRANSCRIPT-ID-FROM-LOG"}}}'
#### 获取录制URL
获取特定会议录制的限时下载URL。使用通知日志中的userId、meetingId和recordingId。
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_recording_url","arguments":{"userId":"USER-ID-FROM-LOG","meetingId":"MEETING-ID-FROM-LOG","recordingId":"RECORDING-ID-FROM-LOG"}}}'
### MCP资源(通过curl)
**列出静态资源:**
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"resources/list","params":{}}'
**列出资源模板:**
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"resources/templates/list","params":{}}'
**读取服务器状态:**
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"resources/read","params":{"uri":"webhook://status"}}'
**阅读特定订阅:**
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"resources/read","params":{"uri":"webhook://subscriptions/SUBSCRIPTION-ID"}}'
**按索引读取通知(0=最新):**
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"resources/read","params":{"uri":"webhook://notifications/0"}}'
**阅读成绩单:**
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"resources/read","params":{"uri":"webhook://transcripts/USER-ID/MEETING-ID/TRANSCRIPT-ID"}}'
**读取录制URL:**
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"resources/read","params":{"uri":"webhook://recordings/USER-ID/MEETING-ID/RECORDING-ID"}}'
### Copilot工作室/代理提示
如果通过Copilot Studio或其他MCP感知代理连接,请使用以下自然语言提示:
|提示|使用的工具|
|--------|-------------|
|“订阅成绩单通知”| `subscribe_to_transcripts` |
|“订阅录制通知”| `subscribe_to_recordings` |
|“显示所有活动的webhook订阅”| `list_subscriptions` |
|“检查我们的订阅是否仍在Graph中处于活动状态”| `list_subscriptions` (带图形检查)|
|“续订成绩单订阅”| `renew_subscription` |
|“删除订阅 ``" | `delete_subscription` |
|“检查通知日志中最近的活动”| `get_notification_log` |
|“显示最近5条通知”| `get_notification_log` |
|“获取最新通知的完整成绩单”| `get_transcript_content` |
|获取用户X、会议Y、记录Z的记录内容| `get_transcript_content` |
|“从最新通知中获取录制下载URL”| `get_recording_url` |
|“总结最近的会议记录”| `get_notification_log` → `get_transcript_content` |
> **小贴士**:代理将自动链接工具,例如首先检查通知日志,提取ID,然后获取转录内容。
### Webhook验证(模拟Graph握手)
curl -s -X POST "http://localhost:8080/notifications?validationToken=test-token-123"
Should return: test-token-123
### 模拟通知
curl -s -X POST http://localhost:8080/notifications \ -H "Content-Type: application/json" \ -d '{ "value": [{ "subscriptionId": "test-sub-id", "changeType": "created", "resource": "users/user-123/onlineMeetings/meeting-456/transcripts/transcript-789", "tenantId": "tenant-abc", "resourceData": { "@odata.type": "#microsoft.graph.callTranscript", "id": "transcript-789" } }] }'
Should return: 202 Accepted
______________________________________________________________________
## Microsoft文档
- [使用Microsoft Graph API获取更改通知](https://learn.microsoft.com/en-us/graph/api/resources/webhooks)
- [创建订阅](https://learn.microsoft.com/en-us/graph/api/subscription-post-subscriptions)
- [在线会议的更改通知](https://learn.microsoft.com/en-us/graph/changenotifications-for-onlinemeeting)
- [订阅资源类型](https://learn.microsoft.com/en-us/graph/api/resources/subscription)
______________________________________________________________________
## 安全注意事项
- **应用程序权限强大** --他们授予对所有用户会议数据的访问权限
- 在可能的情况下,部署网络隔离(ExpressRoute、专用端点)
- 使用 `clientState` 在订阅中验证通知真实性
- 将客户端机密存储在Azure密钥库中,而不是生产环境中的环境变量中
- 监控通知日志中的意外活动
- 此服务器不需要或接受用户承载令牌,它使用自己的应用程序标识
______________________________________________________________________
## 免责声明
此MCP服务器是 **独立开源项目** 作为社区资源而建立。它是基于官方 [Microsoft Graph API的Microsoft学习文档](https://learn.microsoft.com/en-us/graph/api/overview) 并遵循公开记录的模式 [变更通知](https://learn.microsoft.com/en-us/graph/api/resources/webhooks) 和 [在线会议记录/录音](https://learn.microsoft.com/en-us/graph/changenotifications-for-onlinemeeting).
**本项目按“原样”提供,不提供任何明示或暗示的保证。** 对于因使用本软件而产生的任何损害、数据丢失、安全事件或其他问题,作者不承担任何责任。您全权负责:
- 在将代码部署到您的环境中之前,请先对其进行审查和理解
- 保护您的Azure应用程序注册凭据和权限
- 遵守贵组织的数据治理和隐私政策
- 在使用访问所有用户会议数据的应用程序级权限时,确保适当的访问控制
这个项目是 **不隶属于微软、不受微软认可或不受微软支持**Microsoft Graph、Microsoft Teams、Azure和Copilot Studio是微软公司的商标。
使用风险自负。始终首先在非生产环境中进行测试。
______________________________________________________________________
## 许可证
麻省理工学院