Metadata-Version: 2.4
Name: dhcckb-feed-fetcher
Version: 1.0.0
Summary: 网页抓取与 RSS 监控 MCP 工具 — 异步抓取 RSS/Atom/HTML 并返回结构化数据
Project-URL: Repository, https://pypi.org/project/dhcckb-feed-fetcher/
Author: Digital Humanities Platform
License: MIT
Keywords: atom,feed-fetcher,mcp,rss,web-scraping
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Requires-Dist: beautifulsoup4>=4.12
Requires-Dist: cachetools>=5.0
Requires-Dist: charset-normalizer>=3.0
Requires-Dist: feedparser>=6.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: lxml>=5.0
Requires-Dist: mcp>=1.0.0
Requires-Dist: python-dateutil>=2.8
Requires-Dist: tenacity>=8.0
Description-Content-Type: text/markdown

# mcp-feed-fetcher

网页抓取与 RSS 监控 MCP 工具——异步抓取 RSS/Atom/HTML 并返回结构化数据。

## 功能

- **自动内容识别**：自动检测 RSS 2.0 / Atom 1.0 / HTML 内容类型，统一解析为标准结构
- **批量抓取**：支持单 URL 或批量 URL，asyncio 并发请求，结果顺序与输入严格一致
- **智能缓存**：TTL 内存缓存（默认 5 分钟），基于规范化 URL 去重，避免重复网络请求
- **容错与重试**：对网络瞬时错误和 HTTP 5xx 自动指数退避重试，4xx 不重试
- **编码自适应**：优先 Content-Type charset，缺失时 charset-normalizer 自动探测常见编码
- **安全保护**：响应体 5MB 上限截断保护，避免 OOM

## 安装

```bash
pip install mcp-feed-fetcher
# 或
uv add mcp-feed-fetcher
```

## 使用

### MCP Server 启动

```bash
python -m mcp_feed_fetcher
# 或
uv run mcp-feed-fetcher
```

### MCP 客户端配置

```json
{
  "mcpServers": {
    "feed-fetcher": {
      "command": "uv",
      "args": ["run", "mcp-feed-fetcher"]
    }
  }
}
```

## 工具

### fetch_latest_updates

抓取 RSS/Atom feed 或 HTML 文章列表页，返回结构化 JSON。

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `url` | string \| string[] | (必填) | 目标 URL，支持单个或数组 |
| `max_items` | integer | 10 | 每 URL 最多返回条数 (1-50) |
| `content_hint` | "auto" \| "rss" \| "html" | "auto" | 内容类型提示 |
| `max_concurrency` | integer | 5 | 批量抓取最大并发数 (1-10) |
| `force_refresh` | boolean | false | 是否跳过缓存 |
| `timeout_connect` | number | 10.0 | TCP 连接超时秒数 |
| `timeout_read` | number | 30.0 | 读取响应超时秒数 |

## 环境变量

| 变量 | 默认值 | 说明 |
|------|--------|------|
| `MCP_FEED_CACHE_TTL` | 300 | 缓存 TTL（秒） |
| `MCP_FEED_CACHE_MAXSIZE` | 256 | 缓存最大条目数 |
| `MCP_FEED_USER_AGENT` | mcp-feed-fetcher/1.0 | 自定义 User-Agent |
| `MCP_FEED_MAX_REDIRECTS` | 5 | 最大重定向跳数 |
| `MCP_FEED_MAX_BODY_BYTES` | 5242880 | 响应体大小上限（字节） |
| `MCP_FEED_MAX_RETRIES` | 2 | 瞬时失败自动重试次数 |
| `MCP_FEED_EXTRA_HEADERS_JSON` | (空) | 全局自定义请求头 (JSON) |
| `MCP_FEED_LOG_LEVEL` | INFO | 日志级别 |

## 输出格式

单 URL 返回单个结果对象；多 URL 返回数组且顺序与输入一致。

成功结果：
```json
{
  "source_url": "string",
  "resolved_url": "string",
  "fetched_at": "ISO8601",
  "content_type": "rss|atom|html|html_unknown",
  "from_cache": false,
  "truncated": false,
  "total_found": 10,
  "items": [
    {
      "title": "string",
      "publish_date": "ISO8601|null",
      "summary": "string|null",
      "url": "string",
      "authors": ["string"]
    }
  ]
}
```

失败结果：
```json
{
  "source_url": "string",
  "resolved_url": "string|null",
  "fetched_at": "string|null",
  "content_type": null,
  "from_cache": false,
  "truncated": false,
  "total_found": 0,
  "items": [],
  "error": "string",
  "status_code": null,
  "retry_count": null
}
```

## 依赖

- Python >= 3.10
- mcp >= 1.0.0
- httpx >= 0.27.0
- beautifulsoup4 >= 4.12
- lxml >= 5.0
- feedparser >= 6.0
- cachetools >= 5.0
- python-dateutil >= 2.8
- charset-normalizer >= 3.0
- tenacity >= 8.0
