使用说明
siftfeed
技術記事を RSS 等から収集し、多段パイプラインでエンティティ抽出した上で SQLite FTS5 に蓄積する MCP Server。
Claude Code からナレッジベースを全文検索できる。
着想
Siftly の 「多段 AI パイプライン + SQLite FTS5」アーキテクチャを参考にしている。 "siftfeed" = "sift through feeds"(フィードをふるいにかける)。
セットアップ
git clone https://github.com/fugithora812/siftfeed.git
cd siftfeed
npm install
MCP 登録
~/.mcp.json(または プロジェクトの .mcp.json)に追加:
{
"mcpServers": {
"siftfeed": {
"type": "stdio",
"command": "npx",
"args": ["tsx", "/path/to/siftfeed/src/index.ts"],
"env": {
"SIFTFEED_DB_PATH": "/path/to/siftfeed/data/siftfeed.db"
}
}
}
}
SIFTFEED_DB_PATH を省略すると data/siftfeed.db がデフォルトで使われる。
使い方
記事の取り込み
# RSS フィードから取り込み
npm run ingest -- --source rss
# 統計だけ確認
npm run ingest -- --stats
Claude Code からの検索
MCP ツールとして登録すると、どのプロジェクトでも利用できる。
「最近の WebRTC 関連の記事ある?」
「Kubernetes のセキュリティについて何かある?」
Claude Code が search_siftfeed を自動で呼び出し、
蓄積済みの記事から検索結果を返す。
アーキテクチャ
[RSS Feeds (config/feeds.json)]
|
v
+-----------+ +------------------------+
| Ingester |---->| Stage 1: Entity Extrac | (ローカル、API 不要)
| (rss.ts) | | (stage1-extract.ts) |
+-----------+ +------------------------+
| |
v v
+----------+ +------------------+
| Scanner | | entities table |
| 重複排除 | +------------------+
+----------+
|
v
+----------------------------+
| SQLite (better-sqlite3) |
| - articles (本体) |
| - articles_fts (FTS5) |
| - entities (抽出済) |
| - tags (Phase 2) |
| - categories (Phase 2) |
| - cross_references (〃) |
+----------------------------+
|
v
+----------------------------+
| MCP Server (stdio) |
| - search_siftfeed |
| - siftfeed_stats |
+----------------------------+
ディレクトリ構成
siftfeed/
├── bin/
│ └── ingest.ts # CLI エントリ
├── config/
│ ├── feeds.json # RSS フィード定義
│ └── categories.json # カテゴリ定義 (Phase 2 用)
├── src/
│ ├── index.ts # MCP サーバエントリ (stdio)
│ ├── server.ts # ツール登録
│ ├── db/
│ │ ├── schema.ts # SQLite スキーマ + FTS5 定義
│ │ └── connection.ts # DB 接続管理 (WAL モード)
│ ├── ingest/
│ │ ├── adapter.ts # Article 型定義 + ハッシュ計算
│ │ └── rss.ts # rss-parser による取得
│ ├── pipeline/
│ │ ├── scanner.ts # URL ベースの重複排除 + 挿入
│ │ ├── stage1-extract.ts # エンティティ抽出
│ │ └── runner.ts # パイプライン統合
│ └── tools/
│ ├── search.ts # search_siftfeed ツール
│ └── stats.ts # siftfeed_stats ツール
├── tests/ # vitest テスト (21 ケース)
├── data/
│ └── siftfeed.db # SQLite DB (gitignored)
├── package.json
└── tsconfig.json
技術詳細
SQLite FTS5 + trigram tokenizer
全文検索には SQLite の FTS5 拡張を採用し、 トークナイザに trigram を指定している。
CREATE VIRTUAL TABLE articles_fts USING fts5(
title, content, tags, summary_ja,
article_id UNINDEXED,
tokenize='trigram'
);
trigram は入力テキストを 3 文字ずつスライドしてインデックスを構築する。 ICU や MeCab のような外部辞書が不要で、日本語・英語を区別なく検索できる。
トレードオフとして、インデックスサイズが本文の約 3 倍になるが、 10,000 記事で 65 MB 程度なので実用上問題ない。
検索クエリは内部でダブルクォートに囲んで発行している。
これにより、ハイフンを含む full-text のような語句が
FTS5 のカラムフィルタ構文と誤認されるのを防いでいる。
エンティティ抽出(Stage 1)
API を呼ばずにローカルで完結する。以下の 4 種類を正規表現で抽出する。
| 種別 | 方法 | 例 |
|---|---|---|
| library | 既知リスト照合 (80+) | react, kubernetes, claude |
| language | 既知リスト照合 (15) | typescript, rust, go |
| version | semver パターン | v2.1.0, 3.0.0-beta.1 |
| github_repo | URL パターン | viperrcrypto/Siftly |
既知リストはコード内に直接定義しており (stage1-extract.ts)、
追加が必要な場合はここに項目を足すだけで済む。
重複排除
articles.url に UNIQUE 制約を設けており、
同じ URL の記事は scanner.ts で INSERT 前にスキップされる。
日次実行でも既存記事を再処理しない。
DB 接続
better-sqlite3 を WAL モードで使用している。 WAL モードにより、読み取り(MCP ツール)と書き込み(インジェスト CLI)が 同時に走っても互いをブロックしない。
DB パスは環境変数 SIFTFEED_DB_PATH で上書き可能。
未設定の場合は data/siftfeed.db がデフォルト。
MCP ツール
search_siftfeed
FTS5 の MATCH クエリで全文検索を行い、 articles テーブルと JOIN して結果を返す。
| パラメータ | 型 | 説明 |
|---|---|---|
| query | string (必須) | 検索クエリ |
| source | enum | all / x_bookmark / rss / github |
| category | string | カテゴリフィルタ |
| dateFrom | string | 開始日 (YYYY-MM-DD) |
| dateTo | string | 終了日 (YYYY-MM-DD) |
| limit | int (1-50) | 取得件数 (デフォルト: 10) |
siftfeed_stats
パラメータなし。記事数・ソース別内訳・エンティティ数・ トップタグ・最終インデックス日時を返す。
RSS フィード
config/feeds.json で定義。デフォルトで 8 フィードを同梱。
| フィード | category_hint |
|---|---|
| Zenn | - |
| Qiita (人気記事) | - |
| dev.to | - |
| GitHub Blog | developer_tools |
| GCP Release Notes | infra_devops |
| AWS Blog | infra_devops |
| Cloudflare Blog | infra_devops |
| Publickey | - |
フィードを追加するには feeds.json に項目を足すだけでよい。
パフォーマンス
macOS arm64 / Node.js v22 でのベンチマーク結果:
| 指標 | 1,000 記事 | 5,000 記事 | 10,000 記事 |
|---|---|---|---|
| インジェスト | 1.0 s | 4.2 s | 8.9 s |
| スループット | 986/秒 | 1,193/秒 | 1,123/秒 |
| DB サイズ | 6.7 MB | 32.8 MB | 65.5 MB |
| ヒープメモリ | 12.8 MB | 34.5 MB | 58.8 MB |
| 検索 P50 | 1.7 ms | 3.6 ms | 6.7 ms |
| 検索 P95 | 3.5 ms | 6.3 ms | 12.5 ms |
日次運用(20-30 記事/日)では、インジェストは 1 秒未満、 検索は P95 でも数ミリ秒で応答する。
テスト
npm test # vitest (21 ケース)
npx tsc --noEmit # 型チェック
今後のフェーズ
Phase 2: AI Enrichment
Claude Haiku で記事ごとにセマンティックタグ (10-15 個) +
カテゴリ分類 (信頼度スコア付き) + 日本語要約を生成し、
tags / categories テーブルに保存する。
Phase 3: 自動化 + レポート
- launchd / cron で日次 RSS 取り込みを自動実行
- 週次トレンドレポートを Markdown 生成
- X ブックマーク / GitHub trending のインジェスト追加
ライセンス
MIT