会议记录包含通常需要上下文的行动项目:竞争研究、定价查找、功能比较或市场数据。 MCP 管道可以自动从会议记录中提取行动项目,并使用相关搜索数据丰富每个行动项目,将模糊的任务转变为可操作的摘要。本教程使用两种工具构建 MCP 工具服务器:一种将会议记录解析为结构化操作,另一种通过 Web 搜索上下文丰富每个操作。通过 Scavio,搜索丰富化的费用为每个操作项 0.005 美元。
前置条件
- 已安装 Python 3.10+
- mcp 和 openai 软件包已安装
- 来自 scavio.dev 的 Scavio API 密钥
- 用于操作提取的 OpenAI API 密钥
操作指南
步骤 1: 构建动作提取工具
创建一个 MCP 工具,记录原始会议记录,并使用法学硕士提取包含受让人、截止日期和搜索查询的结构化行动项目。
from mcp.server import Server
import json
from openai import OpenAI
server = Server('meeting-actions')
llm = OpenAI()
@server.tool()
async def extract_actions(meeting_notes: str) -> str:
"""Extract action items from meeting notes."""
response = llm.chat.completions.create(
model='gpt-4o-mini',
messages=[{'role': 'system', 'content': '''Extract action items from meeting notes.
Return JSON array with: task, assignee, deadline, search_query (a web search
that would provide useful context for this task).'''},
{'role': 'user', 'content': meeting_notes}],
response_format={'type': 'json_object'},
max_tokens=1000
)
return response.choices[0].message.content步骤 2: 构建搜索丰富工具
创建第二个 MCP 工具,该工具采用操作项并使用相关的网络搜索数据来丰富它。这将一个简单的任务变成了一个上下文简介。
import requests, os
API_KEY = os.environ['SCAVIO_API_KEY']
@server.tool()
async def enrich_action(search_query: str, task_context: str = '') -> str:
"""Enrich an action item with web search context."""
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': API_KEY, 'Content-Type': 'application/json'},
json={'query': search_query, 'country_code': 'us'})
results = resp.json().get('organic_results', [])[:5]
enrichment = {
'query': search_query,
'key_findings': [
{'source': r['link'], 'title': r['title'],
'insight': r.get('snippet', '')}
for r in results
],
'sources_count': len(results)
}
return json.dumps(enrichment, indent=2)步骤 3: 构建完整的管道工具
创建一个组合工具,可在一次调用中完成提取和丰富。这是会议到行动管道的主要入口点。
@server.tool()
async def meeting_to_actions(meeting_notes: str) -> str:
"""Extract action items from meeting notes and enrich each with search context."""
# Step 1: Extract actions
actions_json = await extract_actions(meeting_notes)
actions = json.loads(actions_json).get('actions', [])
# Step 2: Enrich each action
enriched = []
for action in actions:
search_query = action.get('search_query', action.get('task', ''))
enrichment_json = await enrich_action(search_query, action.get('task', ''))
enrichment = json.loads(enrichment_json)
enriched.append({
**action,
'enrichment': enrichment
})
result = {
'total_actions': len(enriched),
'credits_used': len(enriched), # 1 search per action
'cost': f'${len(enriched) * 0.005:.3f}',
'actions': enriched
}
return json.dumps(result, indent=2)步骤 4: 运行 MCP 服务器
启动服务器,以便它可以连接到 Claude Desktop、Cursor 或任何 MCP 客户端。
import asyncio
from mcp.server.stdio import stdio_server
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream)
if __name__ == '__main__':
asyncio.run(main())
# .mcp.json configuration:
# {
# "mcpServers": {
# "meeting-actions": {
# "command": "python",
# "args": ["meeting_actions_server.py"],
# "env": {
# "SCAVIO_API_KEY": "your_key",
# "OPENAI_API_KEY": "your_key"
# }
# }
# }
# }步骤 5: 使用示例会议记录进行测试
输入真实的会议记录并验证管道是否正确提取和丰富了操作。
# Test the pipeline directly (without MCP client):
import asyncio
async def test():
notes = """Product sync 2026-05-13:
- Sarah: Research competitor pricing for CRM tools, need comparison by Friday
- Mike: Look into TikTok API options for our influencer vetting feature
- Lisa: Find best practices for AI Overview optimization, present next week
- Team: Evaluate n8n vs Zapier for our lead gen automation"""
result = await meeting_to_actions(notes)
data = json.loads(result)
print(f'Extracted {data["total_actions"]} actions (cost: {data["cost"]})')
for a in data['actions']:
print(f'\n Task: {a["task"]}')
print(f' Assignee: {a.get("assignee", "unassigned")}')
print(f' Context: {len(a["enrichment"]["key_findings"])} sources found')
asyncio.run(test())Python 示例
import os, json, requests
from openai import OpenAI
llm = OpenAI()
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
def extract_actions(notes):
resp = llm.chat.completions.create(
model='gpt-4o-mini',
messages=[{'role': 'system', 'content': 'Extract action items as JSON array with task, assignee, search_query fields.'},
{'role': 'user', 'content': notes}],
response_format={'type': 'json_object'}, max_tokens=500)
return json.loads(resp.choices[0].message.content).get('actions', [])
def enrich(query):
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
json={'query': query, 'country_code': 'us'})
return [r.get('snippet', '') for r in resp.json().get('organic_results', [])[:3]]
notes = 'Sarah: Research CRM pricing. Mike: Evaluate TikTok APIs.'
for action in extract_actions(notes):
context = enrich(action.get('search_query', action['task']))
print(f'{action["task"]}: {len(context)} sources')JavaScript 示例
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
async function enrich(query) {
const resp = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, country_code: 'us' })
});
const data = await resp.json();
return (data.organic_results || []).slice(0, 3)
.map(r => ({ title: r.title, snippet: r.snippet || '' }));
}
async function main() {
const actions = [
{ task: 'Research CRM pricing', query: 'CRM pricing comparison 2026' },
{ task: 'Evaluate TikTok APIs', query: 'TikTok API options developers 2026' }
];
for (const a of actions) {
const context = await enrich(a.query);
console.log(`${a.task}: ${context.length} sources found`);
}
}
main().catch(console.error);预期输出
Extracted 4 actions (cost: $0.020)
Task: Research competitor CRM pricing comparison
Assignee: Sarah
Context: 5 sources found
Task: Evaluate TikTok API options for influencer vetting
Assignee: Mike
Context: 5 sources found
Task: Research AI Overview optimization best practices
Assignee: Lisa
Context: 5 sources found
Task: Compare n8n vs Zapier for lead generation
Assignee: Team
Context: 5 sources found