-
Notifications
You must be signed in to change notification settings - Fork 0
feat: .nitpicker アーカイブ照会 MCP サーバーの新規実装 #21
Copy link
Copy link
Closed
Description
背景
現状、.nitpicker ファイルの中身を確認するには analyze → report で Google Sheets に出力する必要がある。しかし、現場では「404 のページ一覧がほしい」「jQuery 使ってる?」「alt 未設定の画像は何件?」といった軽い確認を頻繁に行いたい。
MCP サーバーを作り、Claude Desktop 等の AI アシスタント経由で .nitpicker ファイルの中身を自然言語で問い合わせられるようにする。
利用者像
- ウェブディレクター: 納品前チェック、定期監査、SEO/メタデータの品質確認、リンク切れ検出、クライアント報告用データ
- フロントエンドエンジニア: 技術スタック調査(jQuery/React検出)、パフォーマンス(圧縮・CDN・画像最適化)、マークアップ品質、アクセシビリティ
- クライアント企業のウェブ担当者: サイトの健全性確認、リンク切れ、OGP設定漏れ、上司への報告用サマリ
ニーズ一覧
A. サイト全体の概況
- 総ページ数(内部/外部内訳)、ステータスコード分布(200/301/404/500別)
- メタデータ設定率(title/description/canonical/OGP/twitter:card/lang の充足率)
- リソース総数、リダイレクトページ数、スキップページ数
- クロール設定の確認
B. ページ一覧(リッチフィルタ)
- ステータスコード指定(404一覧、5xx一覧など)
- メタデータ欠損フィルタ(title未設定、description未設定、canonical未設定、og:image未設定、twitter:card未設定、lang未設定)
- SEO フラグ(noindex/nofollow付きページ)
- URL/タイトルのパターン検索
- ディレクトリ指定(/blog/ 配下のページ数)
- ソート(URL順、ステータス順、サイズ順)
- ページネーション
C. ページ詳細
- URL指定でメタデータ全項目表示
- 発リンク(anchors)一覧
- 被リンク(referrers)一覧
- リダイレクト元の一覧
D. HTML スナップショット
- URL指定で保存済みHTMLを取得(サイズ制限付き)
E. リンク分析
- 内部リンク切れ一覧(リンク元ページ+リンクテキスト付き)
- 外部リンク切れ一覧
- 孤立ページ(被リンク0の内部ページ)
- 被リンク数上位ページ
- 外部サイトへの発リンク一覧
F. リソース分析
- content-type別の件数・合計サイズ集計
- 外部リソースのドメイン別集計
- URLパターン検索(jQuery/GTM/Analytics等のライブラリ検出)
- 圧縮なしの大きいリソース
- 壊れたリソース(4xx/5xx)
- CDN配信状況
G. 画像分析
- alt属性未設定の画像一覧
- 表示サイズと実サイズの乖離が大きい画像(過大画像)
- width/height未指定の画像(CLS原因)
- lazy loading未設定の大きい画像
- 特定ページの画像一覧
H. 分析結果(analyze実行済みの場合)
- validator別/severity別/rule別の件数集計
- 違反が多いページ上位
- 特定ルール・特定validatorでフィルタした violation 一覧
- analyze未実行時は「データなし」を返す
I. セキュリティ・ポリシー(レスポンスヘッダー経由)
- CSP/X-Frame-Options未設定ページ
- 外部JSスクリプト一覧(サードパーティ棚卸し)
パッケージ構成
@nitpicker/query — アーカイブ照会API
役割: .nitpicker ファイルのライフサイクル管理(open/close)と、上記ニーズ A〜I に対応するクエリ関数群を提供する。MCP サーバーに限らず、プログラムから直接使える汎用 API。
主な責務:
- アーカイブのオープン/クローズ/自動クリーンアップ(シングルアーカイブモデル)
- ニーズ A〜I それぞれに対応するクエリ関数(1関数1ファイル)
- SQLite への直接クエリによる高速なフィルタリング・集計(後述)
依存: @nitpicker/crawler
パフォーマンス設計(重要)
Nitpicker は closed beta で 10,000ページ・500,000レコード・10MB超 のアーカイブを扱ってきた。この規模では「全件取得→アプリ層でフィルタ」は使えない。
方針: ArchiveAccessor に getKnex() メソッドを1つだけ追加し、@nitpicker/query はこの Knex インスタンスを使って SQL レベルでフィルタリング・集計・ページネーションを行う。
- ArchiveAccessor の既存 API で十分な操作(
getHtmlOfPage等)はそちらを使う - 複雑なクエリ(JOIN/GROUP BY/HAVING/WHERE の組み合わせ)は Knex インスタンス経由で直接 SQL 実行
- DB は WAL モードのため、既存の読み書き処理と競合しない
SQL レベルのクエリが必要なケース:
- ステータスコード別集計(
GROUP BY status) - メタデータ欠損フィルタ(
WHERE title IS NULL+ ページネーション) - title/description 重複検出(
GROUP BY title HAVING COUNT(*) > 1) - canonical ≠ url の不一致検出(
WHERE canonical != url) - リソースのドメイン別集計
- 画像テーブルの各種フィルタ(500,000レコードの全件取得は不可)
- レスポンスヘッダー JSON 内の特定キー検索
@nitpicker/mcp-server — MCP サーバー
役割: @nitpicker/query を MCP ツールとして公開する。AI アシスタントが自然言語の質問をツール呼び出しに変換して利用する。
主な責務:
@modelcontextprotocol/sdkで MCP サーバーを構築(stdio トランスポート)@nitpicker/queryのクエリ関数を MCP ツールとしてラップ- 各ツールの description に LLM 向けのガイダンス(「こういう質問にはこのパラメータ」)を記載
- bin エントリポイント(
nitpicker-mcp)を提供
依存: @nitpicker/query, @modelcontextprotocol/sdk, zod
MCP ツール一覧(14個)
| # | ツール名 | 対応ニーズ | 概要 |
|---|---|---|---|
| 1 | open_archive |
— | .nitpicker ファイルを開く |
| 2 | close_archive |
— | アーカイブを閉じる |
| 3 | get_summary |
A | サイト概要(ページ数、ステータス分布、メタデータ充足率) |
| 4 | list_pages |
B | ページ一覧(ステータス/メタデータ欠損/noindex/URL/ディレクトリ等のリッチフィルタ) |
| 5 | get_page_detail |
C | URL指定のページ詳細(メタデータ+発リンク+被リンク) |
| 6 | get_page_html |
D | URL指定のHTMLスナップショット |
| 7 | list_links |
E | リンク分析(リンク切れ/孤立ページ/外部リンク/被リンク上位) |
| 8 | list_resources |
F, I | リソース一覧・集計(ライブラリ検出、圧縮・CDN確認、ドメイン別集計) |
| 9 | list_images |
G | 画像一覧(alt欠損/過大/width未指定/lazy未設定) |
| 10 | get_violations |
H | 分析結果(validator/severity/rule別フィルタ・集計) |
| 11 | find_duplicates |
B | 重複検出(同じ title / description を持つページの組を返す) |
| 12 | find_mismatches |
B, I | フィールド間の不一致検出(canonical≠URL、og:title≠title、og:description≠description 等) |
| 13 | get_resource_referrers |
F | 特定リソースの参照元ページ一覧(「jQuery を使っているのはどのページ?」「GTMが全ページに入っているか?」) |
| 14 | check_headers |
I | レスポンスヘッダーの検査(CSP/X-Frame-Options等の特定ヘッダーが未設定のページ一覧) |
ツール追加の理由
find_duplicates: 重複検出は全ページをグルーピングする操作であり、list_pagesの単純フィルタでは対応できない。LLM が全ページを取得して自力で比較するにはデータ量が多すぎる。find_mismatches: canonical と URL の比較、og:title と title の比較など、2つのフィールド間の不一致を検出するクエリはlist_pagesでは表現できない。SEO チェック・OGP チェックの頻出パターン。get_resource_referrers: 「このライブラリはどのページで使われている?」「Analytics タグは全ページに入っているか?」という問いには、リソース→ページの逆引きが必要。list_resourcesはリソース一覧を返すだけで参照元ページ情報を含まない。check_headers: レスポンスヘッダーは JSON カラムに格納されており、特定ヘッダーの有無を判定するには JSON パースが必要。list_pagesのフィルタとして実装するには責務が広くなりすぎる。
crawler パッケージへの変更
最小限の変更のみ:
- ArchiveAccessor に
getKnex()メソッドを追加: 内部の Database が保持する Knex インスタンスを返す。@nitpicker/queryがこれを使って独自クエリを実行する。 DB_Image型定義をtypes.tsに追加: images テーブルの DB スキーマはdatabase.tsに定義されているが、対応する型が未定義。- ArchiveAccessor の既存メソッド群には変更なし(肥大化を回避)。
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels