GitHub (read-only) について
GitHub (read-only)は、GitHubのリポジトリ、イシュー、プルリクエスト、コミットを照会するPython製MCPサーバーです。ツール選択と引数を評価するベンチマーク機能も含みます。
主な機能
- 016種類の読み取り専用GitHubツール
- 02細粒度の読み取り専用トークン認証
- 03リトライ、レート制限対応、ETagキャッシュ
- 04偽APIを使ったオフラインベンチマーク
- 05ツール説明の評価と最適化
活用シーン
- 01リポジトリ、イシュー、プルリクエスト、コミットの照会
- 02モデルのツール選択と引数の精度測定
- 03MCPベンチマークのオフライン実行
MCP 対応
stdio経由のMCPで読み取り専用GitHubツールを公開します。他のstdio MCPサーバーにも使えるベンチマークハーネスを備えています。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
uvx github-mcp-readonlyGITHUB_TOKENシークレットFine-grained GitHub token with read-only access (Metadata, Contents, Issues, Pull requests).GITHUB_MCP_TOOLSETTool descriptions to serve: v2 (default, optimized), v1 or v1b (benchmark baselines).ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
GitHub MCP サーバー:AI に適切なツールを選ばせる
Claude(または任意の MCP クライアント)が、私の GitHub リポジトリ、イシュー、プルリクエスト、コミットについての質問に答えられるようにする、読み取り専用の Model Context Protocol サーバーです。モデルが適切なツールを適切な引数で選択できる割合を測るベンチマークも付属しています。
ツールの説明を書き直したところ、ローカルの 7B モデルの正答率は 63%から 95%に上がり、調整に使っていない保留質問でも 60%から 90%に上がりました。 アブレーション分析では、この 32 ポイントの向上がどこから生じたのかを示していますが、その大半は説明文によるものではありません。
| 変更 | ポイント | 内容 |
|---|---|---|
リポジトリ名だけでも受け付ける(owner/mcp-bench-app だけでなく mcp-bench-app も可) | +17 | サーバーでの入力処理 |
limit パラメーターの説明に範囲 (1-50) を記載する | +8 | 1つのパラメーターの説明文 |
| ツールの説明を書き直す(使用する場面、使用しない場面、代替手段) | +7 | ツールの説明文 |
v2 で残った誤りは、いずれも API が提供していない機能をモデルが求めたものでした。マージ済み PR、スター数による並べ替え、または未解決イシュー用ツールでのクローズ済みイシューなどです。説明文を改善しても、こうした問題は解決できません。次のステップはスキーマでこれらに対応することです。

作成したもの
- MCP サーバー(Python、
mcpSDK 2.x):stdio 経由で、読み取り専用の 6 つのツールを提供します:list_repositories、get_repository、list_open_issues、search_issues、list_pull_requests、get_recent_commits。 - 最小権限でのアクセス: 読み取り専用のきめ細かな GitHub トークンと
readOnlyHintアノテーションを使用します。トークンはサーバープロセス内にとどまり、モデルに渡されることはありません。 - 本番環境向けの動作: スキーマで検証する入力、バックオフとジッターを使ったリトライ、プライマリおよびセカンダリのレート制限への対応、ETag キャッシュ(304 はレート制限にカウントされません)、リスト系ツールでの正確な合計件数、モデルに復旧方法を伝えるエラーメッセージを備えています。
- 正解が既知のベンチマーク: シードスクリプトで、2 つのリポジトリ、15 件のイシュー、5 件のプルリクエスト、および 2 人の作成者によるコミットを作成します。偽の GitHub API が同じデータをオフラインで提供するため、トークンなしで CI でもベンチマークを実行できます。
- 3 種類の評価: 引数の採点を含むツール選択(60 問)、保留データセット(20 問)、および最終回答をシード済みの事実と照合するマルチステップのエージェント実行(13 問)。
- アブレーション分析(
v1 → v1b → v2):入力処理と説明文の表現を切り分けます。 - 自動説明文オプティマイザー:失敗結果をもとに説明文を書き換え、保留データセットの正答率が低下しない場合にのみ変更を採用します。
- このサーバーに限らず、あらゆる MCP サーバーをベンチマークできるハーネス(examples/)。
- 結果ダッシュボード([docs/](docs/index.html):実行時のすべての質問、呼び出し、エラーを表示します。
- Python 3.10~3.13 のテストと CI(ruff、mypy、pytest、および正しい呼び出しが行われた場合にハーネスが 100%のスコアを出すことを確認するオラクルチェック)。
アーキテクチャ
flowchart LR
U[User] -->|question| C["Claude Desktop<br/>(MCP client)"]
C <-->|"JSON-RPC over stdio<br/>tools/list · tools/call"| S["github-mcp<br/>Python MCP server"]
S -->|"HTTPS · read-only token<br/>ETags · retries"| G[(GitHub REST API)]
E["eval/run_eval.py"] -.->|"same MCP protocol"| S
E -.->|"question + tool schemas"| L["LLM under test<br/>(Ollama or Claude)"]
S -.->|"GITHUB_API_URL (CI)"| F[("fake GitHub<br/>seeded repos")]
| レイヤー | 役割 |
|---|---|
server.py | ツールの登録、引数の検証、正確な合計件数を含む簡潔な JSON の返却 |
descriptions.py | バージョン管理された説明文(v1 ベースライン、v1b アブレーション、v2 最適化版、または JSON ファイル) |
github_client.py | 認証、ページネーション、リトライ、レート制限、ETag キャッシュ、型付きエラー |
eval/ | ベンチマークランナー、引数採点器、シードスクリプト、偽の GitHub、オプティマイザー、グラフ、ダッシュボードのエクスポート |
評価
方法。 各質問を、サーバー独自のツールリストとともにモデルに渡します。これは Claude Desktop が送信する内容とまったく同じです。ハーネスは選択された呼び出しを MCP 経由で実行し、採点します。
- ✅ 正解:期待したツールが選ばれ、呼び出しが成功し、引数も一致(例:「直近 3 日間」→
since_days=3) - 🟡 引数の誤り:適切なツールが選ばれ、呼び出しは成功したものの、引数が誤っているか不足している
- ⚠️ ツールの誤り:別のツールが選ばれた、またはツールが選ばれなかった
- ❌ ツールの失敗:適切なツールが選ばれたものの、呼び出しがエラーを返した
質問は 60 件(ツールごとに 10 件。その 3 分の 1 はツール間で意図的に重複させた領域の質問)です。さらに、v2 の確定後に作成され、チューニングには一切使用していない保留質問が 20 件あります。データには、実際の GitHub 上にあるシード済みベンチマーク用リポジトリを使用しています。モデルは Ollama で温度 0 にしてローカル実行し、各構成で 3 回実行した中央値を報告しています。メインセットの 3 回の実行の差は最大 2 ポイント、保留セットでは最大 5 ポイントでした。
| 構成(qwen2.5:7b) | 正解 | 引数の誤り | ツールの誤り | ツールの失敗 | 入力トークン数 |
|---|---|---|---|---|---|
| v1:曖昧な説明 | 63% | 0% | 8% | 28% | 614 |
| v1b:v1 + リポジトリ名のみ | 80% | 0% | 8% | 12% | 614 |
| v2:説明を書き直し | 95% | 0% | 2% | 3% | 1533 |
| 保留質問での v1 | 60% | 5% | 15% | 20% | 613 |
| 保留質問での v2 | 90% | 0% | 5% | 5% | 1532 |
偽の GitHub を使ったオフライン実行でも同じ傾向でした(65% / 82% / 95%)。
2 つ目のモデル、llama3.1:8b でも、質問と設定は同じです。
| 構成(llama3.1:8b) | 正解 | 引数の誤り | ツールの誤り | ツールの失敗 | 入力トークン数 |
|---|---|---|---|---|---|
| v1:曖昧な説明 | 32% | 7% | 12% | 50% | 643 |
| v1b:v1 + リポジトリ名のみ | 47% | 7% | 12% | 35% | 643 |
| v2:説明を書き直し | 92% | 5% | 2% | 2% | 1559 |
| 保留質問での v2 | 95% | 0% | 0% | 5% | 1558 |
Llama は v1 でも 88% の確率で適切なツールを選びました。問題は引数でした。上限が 50 のツールに limit=100 を何度も指定し、単独の名前が求められるところに owner/repo を渡していました。qwen に有効だった修正(単独の名前、明示した上限値の範囲)は Llama にはさらに効果がありました。そのため、モデルを問わず得られる教訓は、ツールの機能だけでなく、引数の制約も明記することです。
エージェントモード(複数ステップの質問 13 件。回答はシード済みデータと照合):v1 62%、v2 69%。 質問が 13 件の場合、回答 1 件で 8 ポイントになるため、この差は誤差の範囲内です(オフラインでは逆の結果になりました)。
説明の改善にかかるコスト: v2 では、リクエストごとに入力トークンが約 920 個増えます(614 → 1533)。
質問ごと、実行ごとの生データ(JSON の 1 行につき 1 件):eval/results/。
独自の MCP サーバーをベンチマークする
このハーネスは、このサーバー専用ではありません。stdio MCP サーバーを起動するコマンドと、質問を記載した JSONL ファイルを渡してください。
python eval/run_eval.py --server "npx -y @modelcontextprotocol/server-filesystem ." \
--questions my_questions.jsonl --domain "the user's files" --backend ollama --runs 3
examples/ には、質問 10 件を含む小さなメモ用サーバーと、質問のフォーマットがあります。
意思決定ファイル
1. モデルが誤ったツールを選んだ理由
v1b の実行で毎回(各 3 回の実行すべて)誤ったツールが選ばれたケースと、v2 での対応:
| 質問 | 期待 → 選択 | 根本原因 | v2 での対応 |
|---|---|---|---|
| 「ポートフォリオサイトのリポジトリの正確な名前は何ですか?」 | list_repositories → get_repository | v1 の「リポジトリに関する情報を取得します」という説明により、一覧表示ではなく portfolio-website という名前を推測するよう促していました | 修正済み |
| 「長い間プッシュしていないリポジトリはどれですか?」 | list_repositories → get_recent_commits | 「リポジトリの最近のアクティビティを取得します」が回答そのものに聞こえ、最後のプッシュ日時順にリポジトリを並べ替えられることが説明されていませんでした | 修正済み |
| 「mcp-bench-app にはどのトピックがタグ付けされていますか?」 | get_repository → search_issues | 「GitHub を検索します」という説明が、リポジトリに関するあらゆる情報の検索に使えるように受け取られました | 修正済み |
| 「mcp-bench-app で誰かが開いた最新のイシューは何ですか?」 | list_open_issues → search_issues | モデルは検索を選び、created:desc というクエリ構文を作り出しました | 修正済み |
| 「mcp-bench-app でクローズされたイシューはどれですか?」 | search_issues → list_open_issues | モデルは state: "closed" を未解決イシュー用ツールに渡し、ツール名よりも自分の引数を信頼しました | 依然として誤り。保留データでも同様 |
2. アブレーションテストで分かったこと
常に正しいツールを選ぶオラクルを使った場合、v1 のスコアは 83% です。v1 は owner/name を必須とするため、名前だけを指定した質問は 10 件すべて失敗します。つまり、v1 から v2 への改善の一部は、最初から入力処理によるものです。v1b(v1 の説明文+名前だけの指定)によって、両者を切り分けられます。
- v1 → v1b:+17 ポイント。 名前だけを指定した質問 10 件すべてが ❌ から ✅ になりました。説明文はまったく変更していません。
- v1b → v2:+15 ポイント。9 件の質問による改善です。
- 5 件はパラメーターの説明文 1 つによるものです。 v1 の
limitは「件数」とだけ説明していました。モデルは 100 を指定しましたが、スキーマで許可されているのは 50 までのため、呼び出しに失敗しました。v2 では「(1~50)」と示したことで、これら 5 件の質問に成功しました。 - 4 件はツールの説明文によるものです。上の表の最初の 4 行が該当します。
- 5 件はパラメーターの説明文 1 つによるものです。 v1 の
説明が曖昧でも、モデルが誤ったツールを選ぶことはほとんどありませんでした(v1 では正しいツールを 92% の割合で選択)。失敗の大半は、サーバーに拒否された呼び出しによるものでした。
3. 変更した内容
- 各説明文に、返される内容、使用する場面、使用してはいけない場面を記載し、代替ツールも示しました。例:
list_open_issues:「クローズ済みイシュー、キーワード検索、全リポジトリを対象とするイシュー(search_issuesを使用)、またはプルリクエスト(list_pull_requestsを使用)には使用しないでください。」 - 境界を、それぞれ 1 つの軸に沿って相互に重複しないようにしました:オープンかクローズ済みか、単一リポジトリか全リポジトリか、キーワードありかなし、メタデータか履歴か、イシューか PR か。
- すべてのパラメーターに、形式と範囲を例付きで記載しました。 これはツールの説明文よりも重要であることが分かりました。
- 動作上の修正は別途報告します:リポジトリ名だけが指定された場合はユーザーのリポジトリに解決し、一覧表示ツールは 1 ページ分の件数ではなく正確な合計数を返すようにしました。
- エラーメッセージに次の手順を含めました(「正確な名前を確認するには
list_repositoriesを呼び出してください」)。
4. 自動オプティマイザーは過学習し、ガードがそれを検出しました
eval/optimize.py は、学習データでの失敗例をモデルに見せて説明文を書き換えさせ、学習データの精度が上がり、かつ保留データの精度が低下しない場合にのみ候補を採用します。v1 を起点に、qwen2.5:7b でツールの説明文を書き換えた場合(オフラインデータ、4 回のイテレーション):
| イテレーション | 学習(60 件) | 保留データ(20 件) | 採用 |
|---|---|---|---|
| 0(v1) | 65% | 60% | ベースライン |
| 1 | 70% | 55% | いいえ |
| 2 | 67% | 50% | いいえ |
| 3 | 72% | 40% | いいえ |
| 4 | 72% | 40% | いいえ |
書き換えのたびに学習精度は上がりましたが、保留データの精度は下がったため、ガードがすべての書き換えを却下しました。7B モデルが作成したのは、ツールに合った説明文ではなく、直前に見た質問に合った説明文でした。保留データでの確認がなければ、イテレーション 3 は 7 ポイントの改善に見えたでしょう。汎化できたのは、手書きの v2 です。
5. 残っている課題とトレードオフ
- 残り3件の v2 の未達はいずれも、API に存在しない機能を求めています。 プルリクエストの
state: "merged"、リポジトリのsort: "stars"、オープンな課題を取得するツールでのstate: "closed"です。これらに合わせて言い換えることはしませんでした。今回の質問にだけ最適化することになるためです。適切な修正はスキーマ側で行うことです。mergedを受け付ける(merged_atでフィルタリングする)、スター数でクライアント側ソートする、課題ツールで state を指定できるようにする、といった対応です。 - 説明を長くすると、リクエストあたり約920トークン増えます。 ツールが6個なら、その価値はあります。ツールが数十個ある場合は、ツール検索と遅延読み込みに移行します。
- エージェントモードの数値を評価するには、さらに多くの質問が必要です(13件では少なすぎます)。
- ページネーションはリストあたり500件(5ページ)で停止します。それを超える合計件数は、下限として報告されます。
使用方法
Claude Desktop から claude_desktop_config.json に以下を追加します(または、この例のように、command をローカルインストール先に指定します)。
{
"mcpServers": {
"github": {
"command": "uvx",
"args": ["--from", "git+https://github.com/AbdulMuhaiminKhan/github-mcp", "github-mcp"],
"env": { "GITHUB_TOKEN": "github_pat_... (fine-grained, read-only)" }
}
}
}
Docker を使用する場合:docker build -t github-mcp . を実行し、続いて
claude_desktop_config.docker.example.json を使用します。
GUIDE.md では、トークンの権限、シードスクリプト、評価ワークフロー全体について説明しています
(PowerShell については WINDOWS.md を参照してください)。
ベンチマークを自分で実行する
python3 -m venv .venv && source .venv/bin/activate
pip install -e '.[dev,eval,plot]'
pytest -q
# No token needed: the offline benchmark repos and a free local model
ollama pull qwen2.5:7b
python eval/run_eval.py --fake-github --toolset v1 --runs 3
python eval/run_eval.py --fake-github --toolset v2 --runs 3
python eval/run_eval.py --fake-github --toolset v2 --questions eval/heldout.jsonl
python eval/run_eval.py --fake-github --mode agent --toolset v2
# Against real GitHub: seed the repos once (see GUIDE.md), then drop --fake-github
python eval/seed_repos.py
# Rebuild the chart and the dashboard from your results
python eval/plot_results.py eval/results/select-*.jsonl -o docs/results.png
python eval/export_dashboard.py
技術スタック
Python 3.10+ · MCP Python SDK 2.x · httpx · pydantic · GitHub REST API · pytest · ruff · mypy · GitHub Actions · 評価用の Ollama / Anthropic API · matplotlib · バニラ JS ダッシュボード
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。