
作者: HOS(安全风信子) 日期: 2026-02-03 主要来源平台: ModelScope 摘要: HotNews MCP 作为基于 MCP 协议的实时热点聚合服务,实现了一键接入 9 大中文平台热榜的能力,为 AI 模型提供标准化的热点数据。本文深入解析其技术架构、实现原理与工程实践,揭示其如何解决传统热点采集的多平台异构、实时性差、格式不统一等痛点,并提供完整的 ModelScope 创空间部署方案。
在 AI 时代,实时获取高质量的热点信息对于模型训练、内容生成与决策支持至关重要。传统的热点采集方案面临着诸多挑战:
ModelScope 社区推出的 HotNews MCP 服务器正是为了解决这些痛点而生。作为基于 MCP(ModelScope Compute Protocol)协议的标准化服务,它实现了:
根据 ModelScope 魔搭日报的最新动态,HotNews MCP 服务器已正式上线,为开发者提供了便捷的热点数据获取方案。
HotNews MCP 服务器采用分层架构设计,主要包含以下核心组件:

系统架构说明:
MCP 协议是 ModelScope 自研的服务通信协议,基于 HTTP/2 与 gRPC 构建,具有以下特点:
# MCP 服务注册示例
class HotNewsMCPServer:
def __init__(self):
self.service_id = "@wopal-cn/mcp-hotnews-server"
self.version = "1.0.0"
self.endpoints = [
{
"name": "get_hotnews",
"method": "GET",
"path": "/api/hotnews",
"params": {
"platform": "string",
"limit": "integer",
"category": "string"
}
}
]
def register_service(self):
# 注册到 ModelScope MCP 服务中心
pass各平台采集器采用适配器模式,统一接口下实现不同平台的采集逻辑:
# 多平台采集器基类
class BaseCollector:
def __init__(self, platform):
self.platform = platform
self.headers = self._get_headers()
self.cookies = self._get_cookies()
def collect(self, limit=50):
raise NotImplementedError
def _get_headers(self):
return {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
def _get_cookies(self):
return {}
# 知乎采集器
class ZhihuCollector(BaseCollector):
def __init__(self):
super().__init__("zhihu")
def collect(self, limit=50):
# 知乎热榜采集逻辑
url = "https://www.zhihu.com/hot"
# 实现采集逻辑
pass采用加权评分机制,综合考虑多维度指标:
def calculate_hotness(item, platform):
"""计算热度指数"""
# 基础分数
base_score = 0
# 各平台权重配置
platform_weights = {
"zhihu": {"vote": 1.0, "comment": 0.8, "collect": 0.5},
"weibo": {"like": 0.5, "comment": 1.0, "repost": 1.2},
"bilibili": {"view": 0.1, "like": 0.8, "comment": 1.0, "coin": 0.6}
}
# 计算基础分数
weights = platform_weights.get(platform, {})
for metric, weight in weights.items():
if metric in item:
base_score += item[metric] * weight
# 时间衰减因子
time_decay = calculate_time_decay(item.get("timestamp", time.time()))
# 最终热度指数
hotness = base_score * time_decay
return round(hotness, 2)
def calculate_time_decay(timestamp):
"""计算时间衰减因子"""
hours_passed = (time.time() - timestamp) / 3600
# 采用指数衰减
decay = math.exp(-0.1 * hours_passed)
return max(0.1, decay) # 最低保留10%热度将各平台异构数据转换为标准化的 Markdown 格式:
def normalize_to_markdown(items, platform):
"""将采集数据转换为Markdown格式"""
markdown = f"# {platform} 热榜\n\n"
for i, item in enumerate(items, 1):
markdown += f"## {i}. {item['title']}\n"
markdown += f"- 热度: {item['hotness']}\n"
markdown += f"- 链接: {item['url']}\n"
markdown += f"- 来源: {platform}\n"
markdown += f"- 时间: {item['time']}\n"
if 'summary' in item:
markdown += f"- 摘要: {item['summary']}\n"
markdown += "\n"
return markdownHotNews MCP 服务器的完整工作流程如下:
存储 缓存 处理器 采集器 MCP接口层 客户端 存储 缓存 处理器 采集器 MCP接口层 客户端 #mermaid-svg-KCaEgRvfQ3u9CstK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-KCaEgRvfQ3u9CstK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KCaEgRvfQ3u9CstK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KCaEgRvfQ3u9CstK .error-icon{fill:#552222;}#mermaid-svg-KCaEgRvfQ3u9CstK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KCaEgRvfQ3u9CstK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KCaEgRvfQ3u9CstK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KCaEgRvfQ3u9CstK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KCaEgRvfQ3u9CstK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KCaEgRvfQ3u9CstK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KCaEgRvfQ3u9CstK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KCaEgRvfQ3u9CstK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KCaEgRvfQ3u9CstK .marker.cross{stroke:#333333;}#mermaid-svg-KCaEgRvfQ3u9CstK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KCaEgRvfQ3u9CstK p{margin:0;}#mermaid-svg-KCaEgRvfQ3u9CstK .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-KCaEgRvfQ3u9CstK text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-KCaEgRvfQ3u9CstK .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-KCaEgRvfQ3u9CstK .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-KCaEgRvfQ3u9CstK .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-KCaEgRvfQ3u9CstK .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-KCaEgRvfQ3u9CstK #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-KCaEgRvfQ3u9CstK .sequenceNumber{fill:white;}#mermaid-svg-KCaEgRvfQ3u9CstK #sequencenumber{fill:#333;}#mermaid-svg-KCaEgRvfQ3u9CstK #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-KCaEgRvfQ3u9CstK .messageText{fill:#333;stroke:none;}#mermaid-svg-KCaEgRvfQ3u9CstK .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-KCaEgRvfQ3u9CstK .labelText,#mermaid-svg-KCaEgRvfQ3u9CstK .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-KCaEgRvfQ3u9CstK .loopText,#mermaid-svg-KCaEgRvfQ3u9CstK .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-KCaEgRvfQ3u9CstK .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-KCaEgRvfQ3u9CstK .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-KCaEgRvfQ3u9CstK .noteText,#mermaid-svg-KCaEgRvfQ3u9CstK .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-KCaEgRvfQ3u9CstK .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-KCaEgRvfQ3u9CstK .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-KCaEgRvfQ3u9CstK .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-KCaEgRvfQ3u9CstK .actorPopupMenu{position:absolute;}#mermaid-svg-KCaEgRvfQ3u9CstK .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-KCaEgRvfQ3u9CstK .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-KCaEgRvfQ3u9CstK .actor-man circle,#mermaid-svg-KCaEgRvfQ3u9CstK line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-KCaEgRvfQ3u9CstK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} alt [缓存命中] [缓存未命中] 请求热点数据 认证授权 检查缓存 返回缓存数据 触发采集任务 多平台并行采集 原始数据 数据清洗 热度计算 格式标准化 更新缓存 存储历史数据 处理后数据 返回Markdown格式热点
方案 | 平台覆盖 | 实时性 | 格式标准化 | 热度评估 | 部署难度 | 维护成本 | API 易用性 |
|---|---|---|---|---|---|---|---|
HotNews MCP | 9大平台 | 秒级更新 | 标准化Markdown | 统一热度指数 | 低 | 低 | 简单REST API |
传统爬虫 | 自定义 | 分钟级 | 需自行处理 | 无统一标准 | 高 | 高 | 需自行开发 |
第三方API | 有限 | 分钟级 | 部分标准化 | 平台自有标准 | 中 | 中 | 依赖第三方 |
RSS订阅 | 有限 | 小时级 | 标准化XML | 无热度评估 | 低 | 低 | 需解析XML |
商业服务 | 全面 | 秒级 | 标准化 | 专业评估 | 高 | 高 | 简单但付费 |
参考链接:
附录(Appendix):
配置项 | 推荐值 | 说明 |
|---|---|---|
Python版本 | 3.8+ | 运行环境 |
内存 | 4GB+ | 缓存与并发处理需求 |
CPU | 2核+ | 多平台并行采集 |
Redis | 6.0+ | 热点数据缓存 |
MongoDB | 4.0+ | 历史数据存储 |
采集间隔 | 30秒 | 平衡实时性与平台限制 |
缓存过期 | 5分钟 | 热点数据缓存时间 |
# app.py
import gradio as gr
import requests
import time
import markdown
# MCP服务地址
MCP_SERVER_URL = "https://modelscope.cn/mcp/servers/@wopal-cn/mcp-hotnews-server"
# 支持的平台列表
PLATFORMS = ["all", "zhihu", "weibo", "bilibili", "baidu", "toutiao", "douyin", "kuaishou", "xiaohongshu", "tencent"]
def get_hotnews(platform, limit):
"""获取热点数据"""
try:
# 构建请求参数
params = {
"platform": platform,
"limit": limit
}
# 发送请求
response = requests.get(f"{MCP_SERVER_URL}/api/hotnews", params=params, timeout=10)
response.raise_for_status()
# 获取Markdown格式数据
data = response.text
# 转换为HTML格式以便在界面中显示
html = markdown.markdown(data)
return html, f"获取成功!更新时间:{time.strftime('%Y-%m-%d %H:%M:%S')}"
except Exception as e:
return f"获取失败:{str(e)}", f"错误时间:{time.strftime('%Y-%m-%d %H:%M:%S')}"
# 创建Gradio界面
with gr.Blocks(title="HotNews MCP 热点聚合服务") as demo:
gr.Markdown("# HotNews MCP 热点聚合服务")
gr.Markdown("基于ModelScope MCP协议的实时热点聚合服务,支持9大中文平台热榜")
with gr.Row():
with gr.Column(scale=2):
platform = gr.Dropdown(
choices=PLATFORMS,
value="all",
label="平台选择",
info="选择要获取的平台热榜"
)
limit = gr.Slider(
minimum=5,
maximum=50,
value=20,
step=5,
label="获取数量",
info="每个平台获取的热点数量"
)
get_button = gr.Button("获取热点", variant="primary")
with gr.Column(scale=1):
status = gr.Textbox(label="状态", interactive=False)
result = gr.HTML(label="热点数据", height=600)
# 绑定事件
get_button.click(
fn=get_hotnews,
inputs=[platform, limit],
outputs=[result, status]
)
# 添加示例
gr.Examples(
examples=[
["all", 20],
["zhihu", 10],
["weibo", 15],
["bilibili", 10]
],
inputs=[platform, limit],
outputs=[result, status],
fn=get_hotnews
)
if __name__ == "__main__":
demo.launch(share=True)# requirements.txt
gradio==4.44.0
requests==2.31.0
markdown==3.5.0
# 可选依赖
redis==5.0.1
pymongo==4.6.2# Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 7860
CMD ["python", "app.py"]app.py、requirements.txt文件python app.py关键词: HotNews MCP, ModelScope, 热点聚合, MCP协议, 实时数据, 多平台采集, Gradio部署, 热度计算