Skip to content

feat: add list_my_notes / get_note_stats / list_note_likes tools#1

Open
smithshiro wants to merge 1 commit into
Go-555:mainfrom
smithshiro:feat/stats-tools
Open

feat: add list_my_notes / get_note_stats / list_note_likes tools#1
smithshiro wants to merge 1 commit into
Go-555:mainfrom
smithshiro:feat/stats-tools

Conversation

@smithshiro

@smithshiro smithshiro commented Apr 8, 2026

Copy link
Copy Markdown

何ができるようになるか

このPRを入れると、note-post-mcp が**「記事を投稿するだけ」から「自分の note 全体をLLMから確認できる」**ようになります。

具体的には、Claude / Cursor などの MCP クライアントから自然言語で以下のようなことが聞けるようになります:

  • 「今月公開した記事、どれが一番読まれてる?」
  • 「先週の記事、誰がスキしてくれた?フォロワー数が多い人いる?」
  • 「自分の全記事のスキ数合計は?平均コメント数は?」
  • 「"AI" のハッシュタグを付けた記事の閲覧数ランキングを作って」
  • 「一番反応が良かった記事を分析して、次の記事のネタを提案して」

既存の認証 (~/.note-state.json) をそのまま使うので追加のセットアップは不要です。投稿系の publish_note / save_draft1行も変更していません


追加する3つのツール

1. list_my_notes — 自分の記事一覧を取得

公開済みの自分の記事を、タイトル・URL・公開日・スキ数・コメント数・ハッシュタグ・サムネイル付きで返します。include_views: true を付けると閲覧数 (PV) も付与されます。

こんな使い方ができます:

  • ダッシュボードを開かなくても LLM に「今月の記事まとめて」と聞くだけでサマリーが出せる
  • CSV / Markdown テーブルへの変換や集計を LLM にそのまま任せられる
  • 全記事を all_pages: true で一括取得してから LLM に分析させる

入力例:

{
  "name": "list_my_notes",
  "arguments": { "all_pages": true, "include_views": true }
}

返り値のイメージ (実アカウントで取得した本物の例):

{
  "success": true,
  "urlname": "fresh_wolf5070",
  "count": 6,
  "notes": [
    {
      "id": 154189701,
      "key": "n4cd1b857e601",
      "title": "LINEに話しかけるだけで、本格LPが自動で完成する仕組みを作った",
      "url": "https://note.com/fresh_wolf5070/n/n4cd1b857e601",
      "publish_at": "2026-04-04T18:46:56+09:00",
      "like_count": 5,
      "comment_count": 0,
      "view_count": 30,
      "hashtags": ["#AI", "#個人開発", "#LINE公式アカウント", "#イベント告知", "#LP制作"],
      "thumbnail": "https://assets.st-note.com/production/uploads/images/.../rectangle_large_type_2_....png"
    }
  ]
}

💡 urlname は省略するとログイン中ユーザーから自動検出します (note.com のホームページの __NUXT__ state から抽出)。他ユーザーの公開記事を見たい場合は urlname: "<相手のurlname>" を指定すれば OK です。


2. get_note_stats — 特定の記事の詳細統計を取得

1 記事に対してスキ数 (匿名含む)、コメント数、SNS シェア内訳、ハッシュタグ、著者情報などをまとめて返します。include_views: true で自分の記事に限り閲覧数も付与します。

こんな使い方ができます:

  • 特定の記事の反響を Claude に詳しく分析させる
  • 「この記事のシェア内訳を見て、どの SNS で拡散されてるか教えて」と聞く
  • 他人の note URL を渡して「この記事のリアクションどう?」と参考にする

入力例 (URL / key どちらでも OK):

{
  "name": "get_note_stats",
  "arguments": {
    "note": "https://note.com/fresh_wolf5070/n/n4cd1b857e601",
    "include_views": true
  }
}

返り値のイメージ:

{
  "success": true,
  "note": {
    "id": 154189701,
    "key": "n4cd1b857e601",
    "title": "LINEに話しかけるだけで、本格LPが自動で完成する仕組みを作った",
    "url": "https://note.com/fresh_wolf5070/n/n4cd1b857e601",
    "publish_at": "2026-04-04T18:46:56.000+09:00",
    "created_at": "2026-04-04T16:24:44.000+09:00",
    "like_count": 5,
    "anonymous_like_count": 0,
    "comment_count": 0,
    "share_total_count": 0,
    "share_details": { /* twitter / facebook / line / note / others の内訳 */ },
    "view_count": 30,
    "hashtags": ["#AI", "#個人開発", "#LINE公式アカウント", "#イベント告知", "#LP制作"],
    "user": {
      "id": 1505130,
      "urlname": "fresh_wolf5070",
      "nickname": "Web屋のスミス",
      "follower_count": 12,
      "following_count": 9,
      "note_count": 6
    }
  }
}

3. list_note_likes — その記事にスキを付けた人の一覧を取得

ある記事にスキ (♡) を付けたユーザーのリストを、プロフィール情報付きで返します。

こんな使い方ができます:

  • 「どんな人が読んでくれているか」を把握してペルソナ分析に使う
  • 反応してくれた人のプロフィールを見てお礼の返信やフォローバックに繋げる
  • LLM に「フォロワー数の多い順に並べて」「共通点を分析して」と任せられる

入力例:

{
  "name": "list_note_likes",
  "arguments": { "note": "n4cd1b857e601", "all_pages": true }
}

返り値のイメージ:

{
  "success": true,
  "note_key": "n4cd1b857e601",
  "count": 5,
  "likes": [
    {
      "liked_at": "2026-04-06T17:02:55.000+09:00",
      "user": {
        "id": 32398,
        "urlname": "yumotrip",
        "nickname": "ゆも【Re:spects】",
        "profile_url": "https://note.com/yumotrip",
        "profile_image": "https://assets.st-note.com/...",
        "profile": "【美容×旅×歴史】...",
        "follower_count": 26,
        "following_count": 15,
        "note_count": 42
      }
    }
  ]
}

⚠️ note.com 側の仕様により、anonymous_like_count (匿名のスキ) に該当するユーザー情報は API から返ってこないため、リストには含まれません。件数としては get_note_stats.note.anonymous_like_count で把握できます。


使う側への影響 (Breaking changes)

なし。 既存ツールのシグネチャや挙動は変わりません。新ツール3つが追加されるだけです。

変更ファイル 内容
src/index.ts 新ツールのヘルパー関数・Zodスキーマ・TOOLS配列項目・ハンドラ分岐を追加 (既存関数は未変更)
README.md 新ツールのセクションと使用例を追加
package.json / package-lock.json version 1.0.7 → 1.1.0

設計上のポイント (レビュワー向け)

  1. 既存コードへの影響を最小化
    postToNoteparseMarkdown など既存の関数は一切触っていません。新ツール用のヘルパー (withNoteContext, fetchNoteJson, detectUrlname, fetchAllPvStats) を postToNote 定義の後・Zod スキーマ定義の前に追加しています。

  2. 認証は既存の note-state.json を再利用
    新しい認証フローは追加していません。withNoteContextstorageState 付きで Playwright の BrowserContext を用意し、context.request (APIRequestContext) で note.com の内部 API を叩きます。cookie が自動的に引き継がれるため、追加の設定は不要です。

  3. UI スクレイピングは最小限
    UI 操作が必要なのは urlname 自動検出 (note.com のトップページを1回開いて window.__NUXT__.state から取得) の1回だけです。ユーザーが urlname を明示的に指定すれば、このページロードすらスキップされます。記事一覧・統計・スキユーザー取得はすべて JSON API への直接リクエストです。

  4. 使用しているエンドポイント (すべて非公式内部API)

    ツール エンドポイント 認証
    list_my_notes GET /api/v2/creators/{urlname}/contents?kind=note&page={N} 不要
    list_my_notes (+views) GET /api/v1/stats/pv?filter=all&page={N}&sort=pv 必要 (自分の記事のみ)
    get_note_stats GET /api/v3/notes/{key} 不要
    list_note_likes GET /api/v3/notes/{key}/likes?page={N} 不要
  5. include_views のコスト設計
    閲覧数は /api/v1/stats/pv に全ページリクエストを投げて id → read_count のマップを作り、記事一覧とマージします。記事数が多い場合は複数ページ取得しますが、last_page が boolean / number 両方で返る note 側の揺れにも対応済みです (SAFETY_MAX_PAGES = 200 で無限ループ防止)。

  6. note パラメータの柔軟性
    get_note_stats / list_note_likesnote パラメータは key (例: n04b99fa6a237) でも URL (https://note.com/.../n/nXXXX) でも受け付けます。extractNoteKey で正規化しています。

  7. ページネーション
    list_my_noteslist_note_likes には page / all_pages を用意しました。all_pages: true で全ページ取得、それ以外は 1 ページだけ返します。どちらも SAFETY_MAX_PAGES = 200 の安全装置付きです。


注意事項

  • note.com の非公式 API を利用しているため、将来の仕様変更で動作しなくなる可能性があります (既存の Playwright UI 自動化と同じリスクレベル)。エンドポイントが壊れた場合はログにステータスコードとレスポンスボディの先頭 200 文字を出すようにしています。
  • view_count/api/v1/stats/pv が自分の記事しか返さないため、自分の記事でのみ取得可能です。他ユーザーの記事に対して include_views: true を付けても view_count: null になります。

動作確認

実アカウント (記事6件) で統合テスト実施済み。3ツールすべて正常動作を確認しています。

  • list_my_notes { all_pages: true, include_views: true } → 6件取得 / 閲覧数付与 / urlname 自動検出成功
  • get_note_stats { note, include_views: true } → スキ数・コメント数・シェア数・ハッシュタグ・著者情報・閲覧数を取得
  • list_note_likes { note, all_pages: true } → 5名のスキユーザー (プロフィール付き) を取得
  • ✅ 既存の publish_note / save_draft は未改変につき影響なし
  • npm run build (tsc) が通ることを確認

Test plan

  • npm install && npm run build が成功すること
  • 既存の publish_note / save_draft が引き続き動作すること
  • list_my_notes が urlname 自動検出 + all_pages: true で全記事取得できること
  • list_my_notesinclude_views: true を渡すと閲覧数が含まれること
  • get_note_stats が key でも URL でも同じ結果を返すこと
  • get_note_statsinclude_views: true を渡すと自分の記事のみ閲覧数が含まれること
  • list_note_likes が all_pages でページネーションを行うこと
  • note.com の API が変更された場合、エラーメッセージにステータスコードが含まれること

🤖 Generated with Claude Code

note.com の非公式内部APIを利用して、記事一覧と統計情報を取得する3つの
新しいMCPツールを追加しました。投稿専用だった既存のMCPに加えて、自分の
記事の状況やリアクションを確認できるようになります。

## 追加ツール

- **list_my_notes**: 自分 (または任意のurlname) の記事一覧を取得。
  タイトル、URL、公開日、スキ数、コメント数、ハッシュタグを返します。
  `include_views: true` で /api/v1/stats/pv から閲覧数を追加取得。
  urlname を省略すると note.com のホームから自動検出します。

- **get_note_stats**: 特定記事の統計を /api/v3/notes/{key} から取得。
  スキ数(匿名含む)、コメント数、SNSシェア数、ハッシュタグ、著者情報。
  `include_views: true` で自分の記事に限り閲覧数も付与。

- **list_note_likes**: 特定記事にスキを付けたユーザー一覧を取得
  (/api/v3/notes/{key}/likes)。プロフィール情報付き。匿名スキは除外。

## 実装詳細

- 既存の `note-state.json` (Playwright storage state) を再利用し、
  cookie 認証をそのまま引き継ぐ `withNoteContext` ヘルパーを追加
- `context.request` 経由で内部APIを呼ぶことで UI スクレイピングを
  行わず高速に取得
- urlname 自動検出は `window.__NUXT__.state` から探索
- `note` パラメータは key (nXXXXXX) でも URL でも受け付け可
- ページネーション対応 (`page`, `all_pages`)

## 注意事項

- note.com の非公式API を利用しているため、将来の仕様変更で動作
  しなくなる可能性があります
- `view_count` は自分の記事のみダッシュボードAPIから取得可能です
- `anonymous_like_count` のユーザー情報は note.com が公開して
  いないため list_note_likes の結果には含まれません
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant