Metadata-Version: 2.4
Name: dhcckb-feed-fetcher
Version: 1.0.1
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,syndication,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: cachetools>=5.0
Requires-Dist: feedparser>=6.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: mcp>=1.0.0
Requires-Dist: python-dateutil>=2.8
Requires-Dist: tenacity>=8.0
Description-Content-Type: text/markdown

# dhcckb-feed-fetcher

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

## 功能

- **PEP 723 单文件脚本**：可从源码仓库直接 `uv run` 启动，自动装载全部依赖
- **自动内容识别**：自动检测 RSS 2.0 / Atom 1.0 / HTML 内容类型，统一解析为标准结构
- **批量并发抓取**：支持单 URL 或批量 URL，asyncio + Semaphore 控制并发上限
- **TTL 内存缓存**：cachetools.TTLCache 按规范化 URL 去重（默认 300 秒），命中时返回 `from_cache: true`
- **指数退避重试**：tenacity 对瞬时网络错误和 HTTP 5xx 自动重试（最多 3 次）
- **时间标准化**：python-dateutil 将所有时间字段统一清洗为 ISO 8601 格式
- **Feed 标准化解析**：feedparser 解析 RSS 2.0 / Atom 1.0 订阅源
- **响应体截断保护**：超过 5MB 自动截断，防止内存溢出

## 安装与使用

### 方式一：uvx 直接运行（推荐）

```bash
uvx dhcckb-feed-fetcher
```

### 方式二：通过 uv run 运行源码

```bash
uv run src/mcp_feed_fetcher/server.py
```

### MCP 客户端配置

```json
{
  "mcpServers": {
    "feed-fetcher": {
      "command": "uvx",
      "args": ["dhcckb-feed-fetcher"]
    }
  }
}
```

## 工具

### fetch_url

抓取单个或多个 URL，自动检测内容类型（RSS 2.0 / Atom 1.0 / HTML），解析并返回统一结构化的 JSON。

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `url` | string \| string[] | (必填) | 单个 URL 字符串或 URL 列表 |
| `ttl_seconds` | integer | 300 | 缓存生存时间（秒），范围 10-3600 |

## 环境变量

| 变量 | 默认值 | 说明 |
|------|--------|------|
| `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_CONCURRENCY` | 5 | 批量抓取最大并发数 |
| `MCP_FEED_MAX_ITEMS` | 50 | 单 URL 最大条目数 |
| `MCP_FEED_LOG_LEVEL` | INFO | 日志级别 |

## 输出格式

单 URL 返回单个结果对象；多 URL 返回数组。

成功结果：
```json
{
  "source_url": "https://example.com/feed.xml",
  "resolved_url": "https://example.com/feed.xml",
  "fetched_at": "2026-08-02T10:00:00.000000+00:00",
  "content_type": "rss",
  "from_cache": false,
  "truncated": false,
  "total_found": 10,
  "items": [
    {
      "title": "文章标题",
      "publish_date": "2026-08-01T12:00:00+00:00",
      "summary": "文章摘要...",
      "url": "https://example.com/article/1",
      "authors": ["作者名"]
    }
  ]
}
```

失败结果：
```json
{
  "source_url": "https://example.com/feed.xml",
  "resolved_url": null,
  "fetched_at": null,
  "content_type": null,
  "from_cache": false,
  "truncated": false,
  "total_found": 0,
  "items": [],
  "error": "HTTP 503: Service Unavailable",
  "status_code": 503,
  "retry_count": 3
}
```

## 依赖

- Python >= 3.10
- mcp >= 1.0.0
- httpx >= 0.27.0
- feedparser >= 6.0
- python-dateutil >= 2.8
- tenacity >= 8.0
- cachetools >= 5.0
