Skip to content

Commit 08bb47d

Browse files
author
root
committed
Wire rate limit transport logger for throttling visibility
Log proactive waits and retry backoff so operators can see when the server is slowing down to avoid GitHub API rate limit lockouts.
1 parent 5ced9fa commit 08bb47d

4 files changed

Lines changed: 10 additions & 6 deletions

File tree

internal/ghmcp/server.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ func createGitHubClients(cfg github.MCPServerConfig, apiHost utils.APIHostResolv
6363

6464
// Construct REST client
6565
rateLimitState := transport.NewRateLimitState()
66+
rateLimitLogger := cfg.Logger.With("component", "rate_limit")
6667

6768
restUATransport := &transport.UserAgentTransport{
68-
Transport: transport.WrapWithRateLimit(http.DefaultTransport, rateLimitState),
69+
Transport: transport.WrapWithRateLimit(http.DefaultTransport, rateLimitState, rateLimitLogger),
6970
Agent: fmt.Sprintf("github-mcp-server/%s", cfg.Version),
7071
}
7172
restClient, err := gogithub.NewClient(
@@ -82,7 +83,7 @@ func createGitHubClients(cfg github.MCPServerConfig, apiHost utils.APIHostResolv
8283
gqlHTTPClient := &http.Client{
8384
Transport: &transport.BearerAuthTransport{
8485
Transport: &transport.GraphQLFeaturesTransport{
85-
Transport: transport.WrapWithRateLimit(http.DefaultTransport, rateLimitState),
86+
Transport: transport.WrapWithRateLimit(http.DefaultTransport, rateLimitState, rateLimitLogger),
8687
},
8788
Token: cfg.Token,
8889
},

pkg/github/dependencies.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,10 +323,11 @@ func (d *RequestDeps) GetClient(ctx context.Context) (*gogithub.Client, error) {
323323
}
324324

325325
// Construct REST client
326+
rateLimitLogger := d.obsv.Logger().With("component", "rate_limit")
326327
restClient, err := gogithub.NewClient(
327328
gogithub.WithHTTPClient(&http.Client{
328329
Transport: &transport.UserAgentTransport{
329-
Transport: transport.WrapWithRateLimit(http.DefaultTransport, d.rateLimits.Get(token)),
330+
Transport: transport.WrapWithRateLimit(http.DefaultTransport, d.rateLimits.Get(token), rateLimitLogger),
330331
Agent: fmt.Sprintf("github-mcp-server/%s", d.version),
331332
},
332333
}),
@@ -352,10 +353,11 @@ func (d *RequestDeps) GetGQLClient(ctx context.Context) (*githubv4.Client, error
352353
// We use NewEnterpriseClient unconditionally since we already parsed the API host
353354
// Wrap transport with GraphQLFeaturesTransport to inject feature flags from context,
354355
// matching the transport chain used by the remote server.
356+
rateLimitLogger := d.obsv.Logger().With("component", "rate_limit")
355357
gqlHTTPClient := &http.Client{
356358
Transport: &transport.BearerAuthTransport{
357359
Transport: &transport.GraphQLFeaturesTransport{
358-
Transport: transport.WrapWithRateLimit(http.DefaultTransport, d.rateLimits.Get(token)),
360+
Transport: transport.WrapWithRateLimit(http.DefaultTransport, d.rateLimits.Get(token), rateLimitLogger),
359361
},
360362
Token: token,
361363
},

pkg/http/transport/rate_limit.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ type RateLimitTransport struct {
5555
Logger *slog.Logger
5656
}
5757

58-
func WrapWithRateLimit(base http.RoundTripper, state *RateLimitState) http.RoundTripper {
58+
func WrapWithRateLimit(base http.RoundTripper, state *RateLimitState, logger *slog.Logger) http.RoundTripper {
5959
if state == nil {
6060
state = NewRateLimitState()
6161
}
@@ -66,6 +66,7 @@ func WrapWithRateLimit(base http.RoundTripper, state *RateLimitState) http.Round
6666
MinInterval: DefaultMinRequestInterval,
6767
MinRemaining: DefaultMinRateLimitRemaining,
6868
MaxRetries: DefaultMaxRateLimitRetries,
69+
Logger: logger,
6970
}
7071
}
7172

pkg/http/transport/rate_limit_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func TestRateLimitTransport_UpdatesStateFromHeaders(t *testing.T) {
2727
t.Cleanup(server.Close)
2828

2929
state := NewRateLimitState()
30-
client := &http.Client{Transport: WrapWithRateLimit(server.Client().Transport, state)}
30+
client := &http.Client{Transport: WrapWithRateLimit(server.Client().Transport, state, nil)}
3131

3232
resp, err := client.Get(server.URL)
3333
require.NoError(t, err)

0 commit comments

Comments
 (0)