morning-brief-mcp
# Morning Brief MCP
独立、确定性的 A 股晨报服务。它不依赖 AlphaAgent、XQ、内部数据库或 LLM Key,
通过标准 MCP stdio transport 暴露现有 `MorningBriefService`,同时保留普通 Python
调用方式。
## 功能
服务暴露 4 个 MCP tools:
- `generate_morning_brief(target_date=None, output_format="json"|"markdown")`:生成完整晨报。
- `get_morning_news(target_date=None, categories=None, limit_per_category=5)`:返回完成窗口过滤、去重、聚类、分类和相关性排序后的事件。
- `get_previous_close_context(target_date=None)`:返回该晨报对应的上一交易日 A 股市场背景。
- `get_news_coverage(target_date=None)`:返回新闻 provider 状态、角色、指标和覆盖情况,不包含原始 payload 或认证信息。
所有 tool 都面向确认的 A 股目标交易日,结果是确定性的来源证据整理,不构成投资建议。
## 环境与安装
- Python 3.11+
- MCP Python SDK `>=2.0.0,<3`(当前验收稳定版:2.0.0)
- `HITHINK_FINANCE_API_KEY`(用于交易日历和上一交易日市场背景)
晨报新闻直接来自国内公开财经 Web provider,不需要 Brave Key。不要提交真实 `.env`:
```powershell
$env:HITHINK_FINANCE_API_KEY="your-key"
```
```bash
python -m venv .venv
# Windows
.venv\Scripts\python -m pip install -e ".[test]"
# macOS/Linux
.venv/bin/python -m pip install -e ".[test]"
```
## 普通 Python 调用
```python
from morning_brief_mcp.renderers.markdown import render_markdown
from morning_brief_mcp.services.morning_brief import MorningBriefService
service = MorningBriefService()
try:
report = service.generate("2026-08-17")
markdown = render_markdown(report)
finally:
service.close()
```
## MCP stdio 启动
安装后直接启动:
```bash
morning-brief-mcp
```
也可使用通用的 `command + args + env` 客户端配置:
```json
{
"mcpServers": {
"morning-brief-mcp": {
"command": "python",
"args": ["-m", "morning_brief_mcp.server"],
"env": {
"HITHINK_FINANCE_API_KEY": "${HITHINK_FINANCE_API_KEY}"
}
}
}
}
```
`target_date` 必须严格使用 `YYYY-MM-DD`。省略时使用 `Asia/Shanghai` 当前日期,
随后仍由 HiThink 交易日历验证;非交易日返回 `target_not_trading_day`,不会静默改日。
日期、参数、配置和上游错误分别返回稳定的 `invalid_request`、
`target_not_trading_day`、`provider_unavailable` 或 `upstream_error` 结构。业务报告的
`status="partial"` 仍是成功的 tool result,例如单个新闻源失败但其他数据足以生成晨报。
stdio server 不向 stdout 打印调试信息;stdout 仅承载 MCP protocol。
## 数据架构
新闻发现默认直接访问国内财经站点的公开 Web 接口:
| Provider | 角色 | 历史能力 | Tier |
| --- | --- | --- | --- |
| 财联社 CLS | primary | `primary_full_window`(`last_time`) | 2 |
| 东方财富 7×24 | primary | `primary_full_window`(`sortEnd`) | 2 |
| 华尔街见闻 | primary | `primary_full_window`(响应 `next_cursor`) | 2 |
| 金十 | supplemental | `supplemental_latest` | 2 |
| MKTNews | supplemental | `supplemental_latest` | 3 |
| 东方财富个股新闻 | supplemental | `supplemental_security`,严格限制标的数 | 2 |
| 巨潮公告 | supplemental | `supplemental_security`,严格限制标的数 | 1 |
只要至少两个不同 upstream domain 的 primary provider 实际翻页到
`news_window.start`,本轮就不会调用 GDELT。只有完整窗口覆盖不足时才使用 GDELT
作为最后 fallback;latest-only 成功不会被计为完整窗口覆盖。
HiThink 只负责交易日历、上一交易日和 previous-close 市场背景,不参与新闻发现。
## 新闻窗口与流水线
晨报窗口固定为上一交易日 `15:00` 到目标交易日 `08:30`,时区为
`Asia/Shanghai`,两个边界均包含。所有 provider 先映射到统一字段:
`id`、`title`、`url`、`canonical_url`、`source`、`domain`、
`published_at`、`description`、`language`、`category`、`tags`、
`source_tier`、`provider`、`raw_source_id`。
之后继续走已有 deterministic pipeline:
`exact time filter → canonicalize → dedup/event cluster → classify → relevance → today_watch`
同一事件的多源报道只展示一个 cluster,并保留 `related_sources` 与
`related_count`。代表项按 Tier、时间和信息完整度确定。description 只保存上游
真实 brief/summary/content snippet/hover,不做程序扩写。
## 限流、失败隔离与安全
每个 domain 共享一个 HTTP session 和 rate limiter。请求具有 timeout、有界重试、
`Retry-After`、指数退避和抖动。东方财富默认串行且最小间隔 1 秒。单一 provider
失败只记录其 status、warning 和 metrics,不会阻断其他 provider。
分页均受 `DOMESTIC_MAX_PAGES` 与 `DOMESTIC_MAX_ITEMS` 限制。每个 provider
记录页数、原始条数、最老时间、停止原因以及 HTTP request/429/403/retry 计数。
API Key 只从环境变量读取;它不会成为 tool 参数,也不会出现在 tool description、
日志、schema 或 MCP result 中。诊断 tool 不返回请求 Header、完整 upstream payload、
预签名 URL 或内部 secret。
## 测试与真实 smoke
默认测试完全离线,所有 HTTP 行为均使用 fixtures/MockTransport:
```bash
PYTHONPATH=src python -m pytest
```
配置 HiThink Key 后,可用官方 MCP Python client 运行真实子进程 smoke,并对比
Service 与 MCP 关键字段:
```bash
python scripts/stdio_smoke.py
```
## 内容与许可说明
这些 provider 使用公开 Web 接口,仅用于数据发现和链接聚合。开源实现许可证不
等于上游新闻内容许可证;生产或商业部署前,使用者必须自行确认各上游服务条款、
抓取政策和内容使用许可。参考实现与许可证记录见
[`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)。
> 本服务用于市场信息整理和研究,不构成投资建议。
## License
本项目采用 Apache License 2.0,详见 [LICENSE](LICENSE)。
第三方代码参考与归属说明见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
TDQS
Scored across 4 tools
Each tool has a distinct role: generating the brief, fetching news events, retrieving previous-close context, and diagnosing news coverage. No two tools appear to target the same resource or action.
Three tools follow a clear get_<noun> pattern, while generate_morning_brief uses a different verb. The deviation is minor and the names remain predictable and readable.
Four tools is well-scoped for a focused morning-brief server. Each tool serves a clear purpose in the brief-generation workflow without unnecessary overlap.
The server covers the full workflow: generating the brief, retrieving source news, retrieving market context, and diagnosing coverage issues. There are no obvious dead ends or missing operations for its stated purpose.