GitHub の MCP サーバーへの接続を肩代わりする薄いサーバー。
呼ぶ側(tsuzuri の runner)はこのサービスの URL だけを知っていればよく、GitHub App の秘密鍵を一切持たない、という形にするための repo。
before: runner ──MCP──> api.githubcopilot.com (runner が App の秘密鍵を持つ)
after: runner ──MCP──> このサービス ──MCP──> api.githubcopilot.com
linear-mcp-wrapper と対になる repo。 中身の作りは揃えてある。
まだサーバーとして動かない。 tsuzuri から認証まわりのコードを退避させただけで、
プロキシ本体(src/main.py)はまだ無い。tsuzuri 側もまだ何も消していないので、
そちらは今までどおり直接 GitHub を見ている。
| ファイル | 出どころ |
|---|---|
src/auth.py |
tsuzuri の runner/src/github.py をそのままコピー(1 文字も変えていない) |
src/config.py |
tsuzuri の runner/src/config.py の GitHub の部分だけ |
src/logs.py |
tsuzuri の runner/src/logs.py から emit だけ |
env/master.yaml |
tsuzuri の runner/env/master.yaml の GitHub の部分だけ |
GITHUB_REPO は持ってきていない。あれは「繋ぐのをやめる口」で、呼ぶ側の判断なので
tsuzuri に残っている。
そのままコピーした副作用。中身の理屈は全部生きているが、参照先の名前だけが古い。
- 「
linear.pyと対になる場所」— そのlinear.pyは linear-mcp-wrapper のsrc/auth.pyになった - 「
config.pyの Linear の項と同じ理由」— 同上 - 「MCP サーバーへの接続ヘッダに使う(
mcp_tools.github)。唯一の呼び出し元。」— ここを呼ぶのは、これから書くプロキシ本体になる
「REST を直接叩くのはトークン交換の 1 本だけ。それ以外を足さないこと」は生きている。 repo が別になって足しやすくなったぶん、むしろここから効く。
- プロキシ本体(
src/main.py)。 ここが本番。素通しの HTTP プロキシでは済まない:- POST のレスポンスが JSON のことも SSE のこともある
(クライアントは
Accept: application/json, text/event-streamで来る) - 別に GET で長寿命の SSE を張る(サーバー→クライアント方向。切れたら再接続してくる)
mcp-session-idとmcp-protocol-versionを両方向で素通しする必要がある- セッション終了は DELETE
- バッファしないこと。
await response.json()で受けると SSE がそこで固まる
- POST のレスポンスが JSON のことも SSE のこともある
(クライアントは
- 呼ぶ側の認証。 クライアントから来る
Authorizationは Cloud Run の OIDC ID token にして、ここで installation token(auth.py)に差し替える。 Cloud Run は--no-allow-unauthenticatedで立てる - ツールの絞り込み(あとで)。 いまは tsuzuri 側の
IMPLEMENT_TOOL_FILTERがget_file_contents,list_commits,get_commitの 3 本に絞っている。動いてから移す
上流のツールを全部そのまま渡すと、呼ぶ側のモデル呼び出しごと落ちる。
GitHub の MCP は 90 本を超えて公開していて、Vertex の function declaration が
受け付けないスキーマが混ざっていると 400 INVALID_ARGUMENT になる(tsuzuri で実測)。
create_branch / push_files / create_or_update_file を許可リストに入れないこと。
レビューを通る前の実装が GitHub へ出ていく。URL が readonly なので二重に締まっているが、
その readonly がこちら側に移ったことで、呼ぶ側からは外せなくなった。
uv syncローカルでは GITHUB_TOKEN(PAT)を入れれば App の交換を通らずに済む。
Cloud Run では App ID + installation ID + 秘密鍵(Secret Manager)を使う。