Summary
The REST client is built with a transport chain (http.DefaultTransport → user-agent → bearer-auth) that has no response-cache or conditional-request layer, so pull-request tools (pull_request_read with get / get_files / get_commits / get_reviews / get_status, and list_pull_requests) issue unconditional GET requests. Repeated identical reads within or across sessions re-download full responses even when nothing has changed; the ETag GitHub returns is never captured or replayed as If-None-Match.
Where
- Client/transport construction (single site):
internal/ghmcp/server.go — createGitHubClients() wires UserAgentTransport{ Transport: http.DefaultTransport } (and BearerAuthTransport) with no caching transport.
- Transport package has only user-agent / bearer / graphql-features round-trippers:
pkg/http/transport/.
- PR tool handlers call
client.PullRequests.Get/ListFiles/ListCommits/ListReviews/List unconditionally: pkg/github/pullrequests.go.
Impact on users
GitHub's REST API supports conditional requests: replaying the previous ETag as If-None-Match returns 304 Not Modified when nothing changed, and 304 responses don't count against the token's primary rate limit. Agentic sessions frequently re-read the same pull request (e.g. get → get_files → get_reviews, retries, multi-step reasoning). Without conditional requests, each re-read is a full response that spends rate-limit budget and bandwidth, making the token's limit easier to hit and slowing tool calls.
Example prompts that trigger repeated reads
Suggested change
Insert an ETag-revalidating http.RoundTripper at the single client-construction site in createGitHubClients(), below the user-agent transport: cache {etag, body} keyed by (auth scope, method, URL), send If-None-Match on GETs, and return the cached body on 304. An always-revalidate ETag transport keeps tool results fresh (no stale window) while turning unchanged reads into cheap 304s. The GraphQL client is unaffected (POST). This keeps results identical while reducing rate-limit pressure and bandwidth.
Summary
The REST client is built with a transport chain (
http.DefaultTransport→ user-agent → bearer-auth) that has no response-cache or conditional-request layer, so pull-request tools (pull_request_readwithget/get_files/get_commits/get_reviews/get_status, andlist_pull_requests) issue unconditionalGETrequests. Repeated identical reads within or across sessions re-download full responses even when nothing has changed; theETagGitHub returns is never captured or replayed asIf-None-Match.Where
internal/ghmcp/server.go—createGitHubClients()wiresUserAgentTransport{ Transport: http.DefaultTransport }(andBearerAuthTransport) with no caching transport.pkg/http/transport/.client.PullRequests.Get/ListFiles/ListCommits/ListReviews/Listunconditionally:pkg/github/pullrequests.go.Impact on users
GitHub's REST API supports conditional requests: replaying the previous
ETagasIf-None-Matchreturns304 Not Modifiedwhen nothing changed, and304responses don't count against the token's primary rate limit. Agentic sessions frequently re-read the same pull request (e.g.get→get_files→get_reviews, retries, multi-step reasoning). Without conditional requests, each re-read is a full response that spends rate-limit budget and bandwidth, making the token's limit easier to hit and slowing tool calls.Example prompts that trigger repeated reads
get_status/get)Suggested change
Insert an ETag-revalidating
http.RoundTripperat the single client-construction site increateGitHubClients(), below the user-agent transport: cache{etag, body}keyed by (auth scope, method, URL), sendIf-None-Matchon GETs, and return the cached body on304. An always-revalidate ETag transport keeps tool results fresh (no stale window) while turning unchanged reads into cheap304s. The GraphQL client is unaffected (POST). This keeps results identical while reducing rate-limit pressure and bandwidth.