googleapis/mcp-toolbox · error

failed to get logger from context

Error message

failed to get logger from context: %w

What it means

validateOpaqueToken begins by extracting the structured logger from the context via util.LoggerFromContext; if no logger is present in ctx, the introspection flow cannot proceed and this wrapped error is returned. It indicates a programming/setup issue rather than a token problem — the caller passed a bare context.Context.

Solutions

  1. Ensure the server's logging middleware runs before auth so the logger is stored in the request context.
  2. In custom code, attach the logger: ctx := util.WithLogger(ctx, logger) before calling ValidateMCPAuth.
  3. If in tests, use the project's context helpers to inject a test logger instead of context.Background().

Example fix

// before
svc.ValidateMCPAuth(ctx, header) // ctx = context.Background()
// after
ctx = util.WithLogger(ctx, slog.Default())
svc.ValidateMCPAuth(ctx, header)
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := util.LoggerFromContext(ctx); err != nil {
    ctx = util.WithLogger(ctx, slog.Default())
}
return svc.ValidateMCPAuth(ctx, header)

Type guard

func ctxHasLogger(ctx context.Context) bool {
    _, err := util.LoggerFromContext(ctx)
    return err == nil
}

Try / catch

claims, err := svc.ValidateMCPAuth(ctx, header)
if err != nil {
    if strings.Contains(err.Error(), "failed to get logger from context") {
        // programmer error: attach logger to ctx before calling auth
        ctx = util.WithLogger(ctx, slog.Default())
        claims, err = svc.ValidateMCPAuth(ctx, header)
    }
    return claims, err
}

Prevention

When it happens

Trigger: ValidateMCPAuth (or another caller) invokes validateOpaqueToken with a ctx that never had a logger attached, so util.LoggerFromContext returns an error which is wrapped here.

Common situations: Custom embedding of the toolbox server that constructs requests without the project's logger middleware, unit tests passing context.Background(), or a request path that bypasses the logging middleware that injects the logger.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/33e1eb658a21044c. Report an issue: GitHub.

Appendix: source

Thrown at internal/auth/generic/generic.go:346

	aud, err := claims.GetAudience()
	if err != nil {
		return nil, &MCPAuthError{Code: http.StatusUnauthorized, Message: "could not parse audience from token", ScopesRequired: a.ScopesRequired}
	}

	scopeClaim, _ := claims["scope"].(string)

	err = a.validateClaims(ctx, iss, aud, scopeClaim)
	if err != nil {
		return nil, err
	}
	return claims, nil
}

// validateOpaqueToken validates an opaque token by calling the introspection endpoint
func (a AuthService) validateOpaqueToken(ctx context.Context, tokenStr string) (map[string]any, error) {
	logger, err := util.LoggerFromContext(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to get logger from context: %w", err)
	}

	introspectionURL := a.introspectionURL
	if introspectionURL == "" {
		introspectionURL, err = url.JoinPath(a.AuthorizationServer, "introspect")
		if err != nil {
			return nil, fmt.Errorf("failed to construct introspection URL: %w", err)
		}
	}

	paramName := a.IntrospectionParamName
	if paramName == "" {
		paramName = "token"
	}

	var req *http.Request
	if a.IntrospectionMethod == "GET" {
		u, err := url.Parse(introspectionURL)

View on GitHub (pinned to 8cc6e09de2)