BigQuery MCP sample stops working after the access token expires

Aperta Adatta ai principianti
#7,217 2 commenti 0 reazioni 1 assegnatario Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
75/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
google-cloud, python
Ambito
api, cloud

Direzione di ricerca

Inizia da contributing/samples/integrations/bigquery_mcp/agent.py e analizza come vengono inizializzati le credenziali e l’header Authorization di McpToolset. Esegui l’esempio o la riproduzione minima, quindi verifica che un processo a esecuzione prolungata possa chiamare correttamente list_dataset_ids dopo la scadenza del token originale, senza essere riavviato.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

mcp

🔴 Required Information

Describe the Bug:

The bigquery_mcp sample (contributing/samples/integrations/bigquery_mcp/agent.py) fetches an
Application Default Credentials access token once, when the module is imported, and passes it as a
fixed Authorization header on the McpToolset. Access tokens expire after about an hour, and
nothing refreshes this one, so in a long-running adk web or adk api_server process every
BigQuery MCP call fails after the first hour until the process is restarted.

The session manager's own ADC refresh does not help here: it is only used on the mTLS path, and it
skips requests that already have an Authorization header.

Steps to Reproduce:

  1. gcloud auth application-default login
  2. Load the sample and call the list_dataset_ids tool: it works.
  3. Keep the same process running for more than an hour and call the tool again.

Expected Behavior:

The toolset keeps working as long as the process runs, refreshing the token when it expires.

Observed Behavior:

The first call works. After the token expires, about an hour later in the same process, the
tool call is rejected, while the same call with a refreshed token still works:

09:12:57 before expiry, current sample: OK, list_dataset_ids returned 52 datasets
09:13:00 before expiry, fixed sample  : OK, list_dataset_ids returned 52 datasets
10:18:17 current sample credentials valid: False
10:18:18 after expiry, current sample : FAILED (tool call rejected)
10:18:20 after expiry, fixed sample   : OK, list_dataset_ids returned 52 datasets

Note that tools/list on this server does not require a valid token, so listing tools still
succeeds with an expired one. The failure only shows on a tool call.

Environment Details:

  • ADK Library Version (pip show google-adk): main (d57c84f1)
  • Desktop OS: macOS
  • Python Version (python -V): 3.11

Model Information:

  • Are you using LiteLLM: No
  • Which model is being used: N/A (the failure is in the MCP call, before the model)

🟡 Optional Information

Regression:

No. The sample has always fetched the token once at import.

Additional Context:

A header_provider that refreshes the credentials when they are no longer valid fixes it, and
works on both the mTLS and the regular endpoint. I have a small PR ready.

Minimal Reproduction Code:

# Calls list_dataset_ids with the headers the sample's toolset holds, waits for
# the token to expire, then calls it again with the same headers.
import asyncio
import datetime

import httpx2
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client

import agent  # contributing/samples/integrations/bigquery_mcp/agent.py

URL = "https://bigquery.googleapis.com/mcp"


async def call_tool(label):
  headers = dict(agent.bigquery_mcp_toolset.connection_params.headers or {})
  client = httpx2.AsyncClient(headers=headers, timeout=60)
  try:
    async with streamable_http_client(URL, http_client=client) as (r, w):
      async with ClientSession(r, w) as session:
        await session.initialize()
        await session.call_tool("list_dataset_ids", {"projectId": "PROJECT_ID"})
    print(label, "OK")
  except Exception as e:
    print(label, "FAILED", type(e).__name__)


async def main():
  await call_tool("before expiry:")
  expiry = agent.credentials.expiry
  while datetime.datetime.utcnow() < expiry + datetime.timedelta(seconds=90):
    await asyncio.sleep(60)
  await call_tool("after expiry: ")


asyncio.run(main())

How often has this issue occurred?:

  • Always (100%)
Lingua principale
Python
Stelle
21.6k
Fork
4k
Merge medio
13h 49m
PR unite (30g)
10

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di google/adk-python

Tutte le issue di google/adk-python

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.