Fix(tools/bigquery-conversational-analytics): fix authentication scope error in Cloud Run (#1381)

## Problem
Fixes #1378 - BigQuery Conversational Analytics tool fails with
`ACCESS_TOKEN_SCOPE_INSUFFICIENT` error in Cloud Run environments while
other BigQuery tools work fine.

## Root Cause
The conversational analytics tool was using `BigQueryTokenSource()` with
limited `bigqueryapi.Scope`, but the Gemini Data Analytics API
(`geminidataanalytics.googleapis.com`) requires broader `cloud-platform`
scope.

## Solution
- Replace ADC token acquisition to use `google.DefaultTokenSource` with
`cloud-platform` scope
- Remove dependency on limited BigQuery scope from source
- Maintain compatibility with existing OAuth flow

## Testing
-  **Local testing confirmed**: Tool now works perfectly
-  **Test script**:
https://github.com/johanesalxd/bq-agent-app/blob/main/setup/mcp_toolbox_ca_issue/test_detailed_error.py
-  **Successful response**: Returns proper schema information and
conversational answers
-  **All BigQuery tool tests pass**: No regression in other tools
-  **Build successful**: No compilation errors

## Impact
- **Fixes**: Cloud Run deployment authentication errors
- **Maintains**: Local development functionality  
- **Preserves**: All existing BigQuery tool functionality

---------

Co-authored-by: Huan Chen <142538604+Genesis929@users.noreply.github.com>
This commit is contained in:
Jo Alex
2025-09-18 07:06:22 +08:00
committed by GitHub
parent 874ee0ca9e
commit 80b7488ad2
2 changed files with 20 additions and 5 deletions

View File

@@ -188,6 +188,10 @@ func (s *Source) BigQueryTokenSource() oauth2.TokenSource {
return s.TokenSource
}
func (s *Source) BigQueryTokenSourceWithScope(ctx context.Context, scope string) (oauth2.TokenSource, error) {
return google.DefaultTokenSource(ctx, scope)
}
func (s *Source) GetMaxQueryResultRows() int {
return s.MaxQueryResultRows
}

View File

@@ -54,7 +54,7 @@ func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.T
type compatibleSource interface {
BigQueryClient() *bigqueryapi.Client
BigQueryTokenSource() oauth2.TokenSource
BigQueryTokenSourceWithScope(ctx context.Context, scope string) (oauth2.TokenSource, error)
BigQueryProject() string
BigQueryLocation() string
GetMaxQueryResultRows() int
@@ -145,6 +145,17 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
InputSchema: parameters.McpManifest(),
}
// Get cloud-platform token source for Gemini Data Analytics API during initialization
var bigQueryTokenSourceWithScope oauth2.TokenSource
if !s.UseClientAuthorization() {
ctx := context.Background()
ts, err := s.BigQueryTokenSourceWithScope(ctx, "https://www.googleapis.com/auth/cloud-platform")
if err != nil {
return nil, fmt.Errorf("failed to get cloud-platform token source: %w", err)
}
bigQueryTokenSourceWithScope = ts
}
// finish tool setup
t := Tool{
Name: cfg.Name,
@@ -155,7 +166,7 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
AuthRequired: cfg.AuthRequired,
Client: s.BigQueryClient(),
UseClientOAuth: s.UseClientAuthorization(),
TokenSource: s.BigQueryTokenSource(),
TokenSource: bigQueryTokenSourceWithScope,
manifest: tools.Manifest{Description: cfg.Description, Parameters: parameters.Manifest(), AuthRequired: cfg.AuthRequired},
mcpManifest: mcpManifest,
MaxQueryResultRows: s.GetMaxQueryResultRows(),
@@ -197,13 +208,13 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken
return nil, fmt.Errorf("error parsing access token: %w", err)
}
} else {
// Use ADC
// Use cloud-platform token source for Gemini Data Analytics API
if t.TokenSource == nil {
return nil, fmt.Errorf("ADC is missing a valid token source")
return nil, fmt.Errorf("cloud-platform token source is missing")
}
token, err := t.TokenSource.Token()
if err != nil {
return nil, fmt.Errorf("failed to get token from ADC: %w", err)
return nil, fmt.Errorf("failed to get token from cloud-platform token source: %w", err)
}
tokenStr = token.AccessToken
}