Teams Digest MCP¶
你需要在当前机器上搭建一个 local-first 的 Microsoft Teams adaptive digest agent。目标是:不依赖 Microsoft Graph API 作为前提条件,优先从本机 Teams 缓存中提取聊天内容,规范化存储到 SQLite,并提供可供 agent 调用的检索和 digest 能力。并且后续需要支持开发成colleagues skill distillation 和msteams新消息整理收集成知识库markdown文件的功能
最终系统应支持以下用户目标:
-
“总结我今天 Teams 里最重要的事情”
-
“过去 24 小时有哪些 decision?”
-
“哪些 action item 分配给我?”
-
“项目 X 最近有什么变化?”
-
“Alice 最近提到过哪些 blocker?”
-
“这个 thread 最终做了什么决定?”
-
“哪些问题还 unresolved?”
-
“找到关于 ticket ABC-123 的相关讨论”
-
“给我一个带 evidence/message references 的 digest,而不是无来源的 summary”
请把系统设计成一个可靠的 retrieval + structured digest system,而不是简单地 dump 消息后全部塞给 LLM。
核心架构:
Teams local data
↓
local extractor
↓
normalization layer
↓
SQLite
├── conversations
├── messages
├── people
├── attachments
├── ingestion_state
└── digest_snapshots
↓
SQLite FTS5
↓
retrieval layer
↓
digest / agent skill
第一阶段不要引入 vector database。优先使用 SQLite FTS5、metadata filtering、时间过滤、conversation filtering、person filtering 和 exact-match retrieval。Teams 数据里项目名、ticket ID、人名、文件名、日期等 lexical signal 很重要。
只有在 lexical retrieval 明显不足时,才把 embedding 作为 optional extension,并且不要让它成为 MVP 的依赖。
-
优先支持 New Teams / Teams 2.x。
-
研究并优先复用现有 local extractor,而不是重新实现所有 Teams cache parsing。
-
首先评估:
-
zaungast
-
msteams-local-mcp
-
Sec42/teams-decoder
-
-
teams-decoder 主要针对旧 Teams,因此不要默认它适用于 New Teams。
-
如果现有工具能可靠输出 Teams messages,则将它们作为 ingestion backend。
-
如果多个 extractor 可用,实现 adapter abstraction,让 backend 可替换。
例如:
interface TeamsExtractor:
discover()
list_conversations()
fetch_messages(since_checkpoint)
fetch_people()
fetch_attachment_metadata()
不要让上层 digest/retrieval 逻辑依赖某个 extractor 的内部 schema。
首先进行 discovery,不要直接假设 Teams cache 路径。 默认:
-
OS win32
-
Teams Teams 2.x
安全约束:
这是 local forensic-style reader,所以:
-
禁止删除或修改 Teams cache
-
禁止写入 Teams application directories
-
禁止上传 Teams 内容到外部服务
-
所有处理默认 local-only
-
如果 Gemini CLI 本身会将 prompt/data 发送到远程模型,避免自动把整个 Teams history 塞入 prompt
-
retrieval 后只给模型必要的最小 message subset
设计 canonical schema。
建议 messages 表至少包含:
messages
-
id
-
external_id
-
conversation_id
-
parent_message_id
-
thread_id
-
sender_id
-
sender_name
-
timestamp
-
edited_timestamp
-
message_type
-
text
-
normalized_text
-
raw_source
-
source_backend
-
source_record_id
-
ingestion_timestamp
conversations
-
id
-
external_id
-
type
-
chat
-
group_chat
-
channel
-
meeting
-
unknown
-
-
title
-
participants
-
team_name
-
channel_name
-
created_at
-
last_activity_at
people
-
id
-
external_id
-
display_name
-
email_or_upn
-
aliases
attachments
-
id
-
message_id
-
name
-
type
-
url
-
local_path
-
mime_type
-
size
-
availability
-
metadata_only
-
local
-
remote
-
unresolved
-
ingestion_state
-
backend
-
conversation_id
-
checkpoint
-
last_ingested_at
digest_snapshots
-
id
-
scope_type
-
scope_id
-
window_start
-
window_end
-
generated_at
-
summary
-
structured_json
-
source_message_ids
-
previous_snapshot_id
创建 FTS5 index,至少支持:
-
message text
-
sender
-
conversation title
-
attachment names
retrieval 必须优先做 hybrid lexical + metadata filtering:
retrieve_messages(
query=None,
since=None,
until=None,
people=None,
conversation=None,
limit=...
)
不要默认返回几百条消息。
增加 thread reconstruction:
read_thread(message_id or thread_id)
需要:
-
parent/reply relationships
-
附近上下文
-
时间顺序
-
sender
-
thread title/context
设计高层 agent tools / CLI commands。
至少实现:
teams search ""
teams recent --since "24h"
teams thread
teams digest --since "24h"
teams digest --conversation --since "7d"
teams decisions --since "7d"
teams actions --since "7d"
teams open-questions --since "7d"
如果更适合,也可以实现 MCP server,但 CLI 必须先工作,方便 Gemini CLI 直接调用。
digest 的核心不是普通 summary。
要求模型把消息转换成以下结构:
{
"summary": "...",
"topics": [
{
"topic": "...",
"summary": "...",
"importance": "high|medium|low",
"evidence": ["message_id"]
}
],
"decisions": [
{
"decision": "...",
"status": "confirmed|tentative|reversed|unclear",
"participants": [],
"timestamp": "...",
"confidence": 0.0,
"evidence": ["message_id"]
}
],
"action_items": [
{
"task": "...",
"owner": "...",
"due": null,
"status": "open|done|unclear",
"confidence": 0.0,
"evidence": ["message_id"]
}
],
"open_questions": [
{
"question": "...",
"owner": null,
"evidence": ["message_id"]
}
],
"blockers": [
{
"blocker": "...",
"owner": null,
"evidence": ["message_id"]
}
],
"important_messages": [
{
"message_id": "...",
"reason": "..."
}
]
}
严格要求 evidence grounding。
每个:
-
decision
-
action item
-
blocker
-
open question
必须尽可能附带原始 message ID。
不要把:
-
suggestion
-
brainstorming
-
tentative proposal
-
question
-
hypothesis
误判成 confirmed decision。
例如:
“maybe we should ship Friday”
不能变成:
“Decision: ship Friday”
除非后续消息明确确认。
confidence 只表示模型对 extraction 的置信度,不代表事实本身的重要性。
实现 incremental digest。
不要每次 digest 都重新读取和总结全部历史。
流程:
previous checkpoint
↓
new messages
↓
retrieve relevant prior context
↓
digest delta
↓
merge with previous structured snapshot
↓
new snapshot
merge 时需要处理:
-
decision 被更新
-
decision 被 reversed
-
action item completed
-
action item reassigned
-
blocker resolved
-
open question answered
保留 temporal history,不要简单覆盖旧状态。
例如:
Decision v1:
Use Redis
later:
Actually switch to Postgres
最终状态应该体现:
-
Redis decision was superseded
-
current decision is Postgres
而不是同时把两者当 active decisions。
attachment 处理必须与 Teams parser 解耦。
Teams local cache 很可能只有:
-
filename
-
attachment metadata
-
SharePoint/OneDrive URL
而没有文件正文。
实现:
AttachmentResolver:
resolve_local_copy()
resolve_synced_onedrive_copy()
get_metadata()
MVP 不要求通过 Graph 自动下载 cloud attachment。
如果本地 OneDrive/SharePoint sync directory 中存在对应文件,可以建立 local_path。
支持后续扩展:
AttachmentContentExtractor:
-
txt
-
md
-
pdf
-
docx
-
pptx
-
xlsx
但 attachment content extraction 不应该阻塞 Teams message ingestion。
对模型上下文严格控制。
不要:
SELECT * FROM messages
然后把全部内容发给 Gemini。
应该:
user intent
↓
query planner
↓
FTS5 + filters
↓
top candidate messages
↓
thread expansion
↓
dedup
↓
context compression
↓
LLM digest
设计 context budget,例如默认最多:
-
50-100 candidate messages
-
必要时扩展 thread
-
超限时先按 conversation/thread 做局部摘要
-
保留 evidence IDs
尤其注意 Teams message noise:
-
emoji/reactions
-
greetings
-
automated notifications
-
meeting join/leave messages
-
quoted duplicate text
-
bot messages
-
repeated link previews
不要简单删除,而是在 normalization 中标记 noise 类型,并默认降低 retrieval priority。
实现 dedup。
Teams cache 中可能出现:
-
同一消息多个 representation
-
edited messages
-
notification copy
-
reply preview
-
quote duplication
canonical message identity 应尽可能依据 stable Teams ID。
如果没有 stable ID,构造 deterministic fingerprint,例如:
conversation_id +
sender +
timestamp +
normalized_text hash
但 fingerprint 只能作为 fallback。
建立可检查性。
每次 digest 应允许用户进一步执行:
teams evidence
并看到:
timestamp
sender
conversation
raw/normalized text
thread context
agent 任何重要结论都应该可以 trace 回原消息。
实现 observability:
teams doctor
输出:
-
detected Teams installation
-
detected backend
-
cache path
-
extractor version
-
message count
-
conversation count
-
earliest/latest message
-
FTS status
-
last ingestion checkpoint
-
attachment statistics
实现:
teams ingest --dry-run
先显示将读取什么、发现多少数据,不写数据库。
再执行:
teams ingest
项目结构建议:
teams-digest/
├── README.md
├── pyproject.toml
├── src/
│ └── teams_digest/
│ ├── cli.py
│ ├── config.py
│ ├── db.py
│ ├── models.py
│ ├── ingestion/
│ │ ├── base.py
│ │ ├── zaungast.py
│ │ ├── local_mcp.py
│ │ └── autodetect.py
│ ├── normalize/
│ │ ├── messages.py
│ │ ├── threads.py
│ │ └── dedup.py
│ ├── retrieval/
│ │ ├── fts.py
│ │ ├── filters.py
│ │ └── context.py
│ ├── digest/
│ │ ├── schema.py
│ │ ├── prompt.py
│ │ ├── generate.py
│ │ └── merge.py
│ └── attachments/
│ ├── resolver.py
│ └── extract.py
├── tests/
└── tools/
语言优先 Python 3.11+。
优先使用标准库和轻量 dependency。
数据库使用 SQLite,不要引入 PostgreSQL 或 external service。
digest 模型执行:
target machine 使用 Gemini CLI。
请设计一个清晰的 Gemini adapter,而不是把 Gemini command hard-code 到业务逻辑里。
例如:
class DigestModel:
def generate(prompt, context) -> StructuredDigest
class GeminiCLIModel(DigestModel):
...
Gemini CLI invocation 必须:
-
有 timeout
-
捕获 exit code
-
捕获 stderr
-
能处理 malformed JSON
-
structured output 校验失败时允许有限次数 repair
-
不自动无限 retry
-
不让 shell injection 进入 command construction
最好通过 stdin 或临时文件提供 prompt/context,不要把大量 Teams 内容直接拼进 shell command 参数。
prompt 中明确要求 Gemini:
-
只根据 supplied evidence 做判断
-
不使用外部知识补足 Teams 中没有的信息
-
区分 confirmed / tentative / unclear
-
必须返回 message IDs
-
缺失信息返回 null / unknown,而不是猜测
对 Gemini 输出使用 Pydantic 或等价 schema validation。
测试至少覆盖:
-
ingest 单条 conversation
-
incremental ingest 不重复写
-
edited message
-
reply/thread reconstruction
-
FTS exact search
-
ticket ID search
-
person + time filter
-
duplicate message handling
-
tentative proposal 不变成 confirmed decision
-
confirmed decision extraction
-
reversed decision merge
-
action completion merge
-
malformed Gemini JSON
-
empty retrieval
-
attachment metadata with no local file
-
local attachment resolution
增加 synthetic fixture,不要测试依赖真实 Teams 数据。
实现过程中不要一次性写完后才测试。
按下面阶段执行:
Phase 1:
-
inspect environment
-
inspect available Teams cache
-
evaluate extractor options
-
write findings
Phase 2:
-
scaffold project
-
SQLite schema
-
canonical models
-
basic ingestion
Phase 3:
-
FTS5 retrieval
-
filters
-
thread reconstruction
Phase 4:
-
Gemini CLI adapter
-
structured digest schema
-
evidence grounding
Phase 5:
-
incremental snapshots
-
decision/action merge
Phase 6:
-
attachment resolver
-
doctor command
-
documentation
每个阶段完成后:
-
run tests
-
report what works
-
report assumptions
-
report known limitations
-
then continue
不要为了“看起来完整”而实现未经验证的 Teams parser。
如果 New Teams 的 local schema 与已有项目不匹配:
-
先保存和描述发现的 schema
-
写最小 reproducible inspection
-
再扩展 adapter
-
不要在不知道结构时猜字段意义
完成后 README 至少包含:
-
architecture
-
installation
-
Teams cache discovery
-
privacy model
-
supported Teams versions
-
ingestion
-
querying
-
digest
-
Gemini CLI configuration
-
attachment limitations
-
troubleshooting
-
data deletion/reset
-
threat model
-
known limitations
最终 acceptance criteria:
我应该可以在 target machine 上执行:
teams doctor
看到 Teams 数据源被检测到。
然后:
teams ingest
把 Teams messages 增量导入本地 SQLite。
然后:
teams search "ABC-123"
得到相关 Teams messages。
然后:
teams digest --since 24h
得到:
-
concise summary
-
topics
-
decisions
-
action items
-
blockers
-
open questions
并且所有重要结论带 message evidence IDs。
然后:
teams evidence
能返回对应原始 Teams message 和必要 thread context。
系统在第二次:
teams ingest
时不能重复导入整个 history。
系统必须 local-first、read-only toward Teams、incremental、traceable、schema-validated。
优先 correctness 和 inspectability
开始时先不要写代码。
先完成: 调研现存开源实现, 理解我们的项目要求, 识别可以借鉴的部分 proposed concrete implementation plan
我们最后部署项目的机器不能从通用源pipinstall, 所以先列出dependency交给user做决策 然后在当前任务中继续实现
当存在不确定性时,明确标注:
-
confirmed
-
inferred
-
unknown
不要伪造 Teams schema、Gemini CLI behavior 或 extractor capabilities。