2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MCPで作る技術記事収集システム #4 — Notion連携と推薦編

Posted at

Phase 4 では、収集・要約した記事を Notion に保存し、蓄積データから パーソナライズ推薦 を行えるように拡張しました。
対象リポジトリ:https://github.com/RuumaLilja/tech-collector-mcp

✍ 本稿は ChatGPT でドラフト生成後、筆者が検証・加筆しています


1. これまでのおさらい

フェーズ 機能 記事
Phase 0 構想・技術選定 #0
Phase 1 Qiita 取得 & MCP 基盤 #1
Phase 2 Gemini API 要約 #2
Phase 3 マルチソース ingest #3
Phase 4 Notion 連携 + 推薦 ← 本記事

2. Notion 連携の概要

  • StoragePort … 抽象ストレージ層。Notion 以外(例:SQLite/Firestore)にも差し替え可能

  • syncService … 単一記事を upsert

  • syncBatchService … 並列同期+進捗表示


3. 簡易パーソナライズ推薦

3-1. コアロジック(要約版)

// src/services/recommenderService.js — essence
import { DECAY_RATE } from '../config/constants.js';
import { fetchAllArticles } from './fetchService.js';

// 1) 発行日が古いほど指数減衰
const decay = d =>
  Math.exp(-DECAY_RATE * ((Date.now() - new Date(d)) / 86400000));

// 2) 読了記事のタグ×評価を重み化
async function tagWeights(storage) {
  const read = await storage.listByStatus('読了', 100);
  return read.reduce((w, a) => {
    if (!a.rating) return w;
    a.tags.forEach(t => (w[t] = (w[t] || 0) + a.rating));
    return w;
  }, {});
}

// 3) 未読記事に「タグ適合度 × 減衰」でスコア付与
export async function getRecommendations({ limit = 10 } = {}, { storage }) {
  const weights = await tagWeights(storage);
  const all     = await fetchAllArticles();

  return all
    .filter(a => !storage.exists(a))              // 未読のみ
    .map(a => {
      const tagScore = a.tags.reduce((s, t) => s + (weights[t] || 0), 0);
      const score    = (tagScore || 1) * decay(a.publishedAt);
      return { ...a, score };
    })
    .sort((a, b) => b.score - a.score)
    .slice(0, limit);
}

なにをしているか

  • 指数減衰 (decay)
    新しい記事ほどスコアが高く、日数が経つと指数関数的に減衰

  • タグ重み (tagWeights)
    ユーザが「★評価」した読了記事 100 件を対象に、タグ × 評価 を加算

  • スコア算出
    未読記事に タグ適合度 × 減衰 を掛け合わせ、上位 N 件を返却。
    タグが合わない場合でも減衰値だけで “純粋な新着度” を確保


4. デモ

4-1. 記事取得 → Notion 保存

tech-collector-mcpall.gif

ユーザー

今週のおすすめ記事を1件ずつストックして

今週のおすすめ記事を各ソースから1件ずつ、合計4件をNotionに正常にストックしました!

ストックした記事:

  1. Qiitaから:セキュリティ関連の記事
  2. Dev.toから:アイデア創出に関する記事
  3. NewsAPIから:Nintendoのゲームセールに関するニュース
  4. HackerNewsから:LLMとQ/kdb+プログラミングに関する技術記事

すべての記事が正常にNotionデータベースに同期されました。Notionで詳細を確認できます。

4-2. おすすめ記事を Notion DBの情報を参考に推薦

tech-collector-mcp-recommend.gif

ユーザー

今までのストックに基づいておすすめ記事を推薦して

📝 あなたのストックに基づいて、おすすめの記事を推薦します!
  1. AWS構成図作成の悩みを一掃!Diagram as Codeで始める"コードで描く"インフラ設計
    👨‍💻 著者: k_adachi_01 (Qiita)
    🏷️ タグ: AWS, diagram_as_code, 生成AI
    📊 評価: 55 点 (いいね27, ストック14)
    📅 公開日: 2025年7月9日

  2. Claude 3.7 vs Gemini 2.5 pro for Coding
    👨‍💻 著者: entelligenceai (Dev.to)
    🏷️ タグ: webdev, programming, ai, javascript
    📊 評価: 21 リアクション, 13 コメント
    📅 公開日: 2025年7月7日

  3. A Smarter Way to Auto-Generate Your Project Docs with AI
    👨‍💻 著者: abubakersiddique771 (Dev.to)
    🏷️ タグ: ai, chatgpt, gemini, deepseek
    📊 評価: 25 リアクション
    📅 公開日: 2025年7月7日


🚀 その他の注目記事

  • Optimizing a Math Expression Parser in Rust — Rustでの数式パーサー最適化
  • Is Gemini 2.5 good at bounding boxes? — AI画像認識の精度検証
  • 国産の無料VPSを試す【Dify】 — 国産VPSサービスの実践レビュー

コミュニティ・ツール系

  • Host Your Own Q&A Community Using Apache Answer — オープンソースQ&Aプラットフォーム
  • スティーブ・ジョブズの「引き算の美学」 — デザイン思考とコミュニケーション

これらの記事は、あなたの過去のストック傾向に基づいて選ばれています。特に AI、プログラミング、AWS 関連の記事が多く推薦されていますね。


5. なぜ Notion 公式 MCP を採用しなかったか?

5-1. プロンプトの揺れを避けたい

  • 公式 MCP はチャット側プロンプトで「テーブル定義取得 → レコード作成」を毎回明示する必要があり、

  • 表現ゆらぎやスキーマ変更時の壊れリスクが高い

5-2. ストレージ多様化に備える

  • StoragePort 抽象層によりアダプタ差し替え可能

  • 公式 MCP 依存がないため、長期保守コストを低減

5-3. 開発速度を優先

  • notion-sdk-js だけで CRUD が完結

  • ツール登録やスキーマ二重管理のコストを回避し、迅速に実装


6. まとめ & 次回予告

  • 収集 → 要約 → 保存 → 推薦 のフロー完成

  • Phase 5 では

    • Slack Bot や Discord と 連携

    • cron / GitHub Actions で毎日自動同期
      へ挑戦予定です


7. 参考文献

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?