Tools
Tools: Building an AI-Native Data Interface with Google ADK, MCP, and BigQuery
2026-01-17
0 views
admin
Introduction ## What This PoC Is Really About ## Why This Problem Is Worth Solving ## A Quick Introduction to Google ADK ## Understanding MCP (Model Context Protocol) ## MCP and BigQuery: Why This Combination Matters ## High-Level Architecture ## How you can try this PoC in your local env ## Why This PoC Goes Beyond a Demo ## Practical Use Cases ## Key Takeaways ## Conclusion ## PoC Shot ## References ## Key Challenge Faced: Authentication & Session Management For many years, enterprise data interaction has followed a predictable pattern. Engineers write SQL, teams build dashboards, and organizations rely on BI tools to understand system behavior, business performance, and costs. While these approaches remain useful, they are increasingly insufficient in modern cloud environments where scale, velocity, and operational complexity demand faster, more intelligent decision-making. From an SRE, platform engineering, and FinOps perspective, the challenge is no longer just accessing data. The challenge is enabling safe, governed, and intelligent interaction with data that supports reliability, cost optimization, and continuous cloud transformation. To address this, I tried a fully working proof of concept (PoC) using Google ADK, Model Context Protocol (MCP), and BigQuery, strictly based on Google’s official documentation and extended with production-grade engineering considerations. This was not a conceptual exercise or a demo-only prototype. The system runs end-to-end and reflects architectural patterns suitable for real enterprise platforms. In this article, I describe what I built, why this architecture matters for modern cloud organizations, and how Google ADK and MCP fundamentally change how AI systems can support SRE, platform, and FinOps workflows at scale. At its core, this PoC explores a simple but powerful idea: What if AI agents interacted with enterprise data the same way production-grade cloud systems are expected to? Rather than embedding SQL logic into prompts or granting broad database access, this PoC demonstrates how an AI agent can: The agent never improvises data access. Every interaction is explicit, policy-aligned, and traceable, which is essential in SRE- and FinOps-driven environments. Many AI + data examples appear impressive but fail under real operational constraints. Common issues include hardcoded SQL in prompts, excessive permissions, and no separation between reasoning logic and execution logic. From an SRE and platform engineering standpoint, these patterns introduce unacceptable risk. From a FinOps standpoint, they obscure cost attribution, accountability, and governance. This PoC takes a different approach. Data access is treated as a platform capability, not a prompt-level shortcut. This distinction is critical for organizations focused on reliability, security, cost efficiency, and sustainable cloud transformation. Google ADK (Agent Development Kit) provides a structured framework for building agentic systems that align well with cloud-native engineering principles. Instead of focusing solely on prompts, ADK formalizes agents, tools, reasoning loops, and context boundaries. For senior engineers and platform architects, ADK feels intuitive. It mirrors how reliable systems are designed: with explicit contracts, modular components, and controlled execution paths. You are not instructing a model to respond once; you are defining how it reasons, when it acts, and what platform capabilities it may invoke. This makes ADK particularly relevant for production systems supporting SRE automation, FinOps analysis, and large-scale cloud operations. MCP is a critical architectural component of this solution. Rather than allowing AI models to directly manipulate external systems, MCP introduces a formal protocol for tool-based interaction. Tools expose schemas, models discover capabilities, and all inputs and outputs are structured and validated. In practice, the model does not need to understand BigQuery's internals. It only needs to understand the operational contract defined by the MCP tool. This design closely aligns with platform engineering best practices and enables AI systems to operate within the same governance boundaries as other production services. Google’s official MCP support for BigQuery is especially impactful because BigQuery is often the system of record for analytics, operational metrics, and cost data. By exposing BigQuery through MCP: The AI agent never becomes a privileged database user. Instead, it behaves as a controlled platform consumer, consistent with how SRE and FinOps systems are expected to operate. At a high level, the PoC architecture looks like this: The most important takeaway here is the separation of concerns. The agent is created using Google ADK primitives. It includes a reasoning loop and the ability to discover and invoke MCP tools. This structure makes the agent predictable and easier to extend over time. Registering BigQuery as an MCP Tool Next, BigQuery is exposed through an MCP server. The server defines exactly what operations are available and how requests should be shaped. This step is where governance really comes into play. The tool definition becomes the contract. The response is structured, predictable, and easy for the agent to interpret. The value of this PoC lies not only in functionality, but in architectural discipline. For SRE, platform engineering, and FinOps leaders, these characteristics are essential. This architectural pattern supports multiple high-impact use cases: The same design scales naturally as organizational maturity grows. Building this PoC reinforced several core principles: This PoC demonstrates that AI-native cloud platforms have moved beyond experimentation. With Google ADK and MCP, it is now possible to build intelligent agents that support reliability engineering, platform operations, and financial governance in a secure and scalable way. For organizations undergoing cloud digital transformation, this approach provides a disciplined foundation for integrating AI into core operational workflows rather than treating it as an isolated experiment. During this PoC, the biggest technical hurdle was authentication. Standard HTTP connections often use static headers. However, Google Cloud OAuth tokens are short-lived (usually 1 hour). If your agent runs longer than that, a static token results in a 403 Forbidden error. To solve this, I implemented a Dynamic Header Provider. Instead of passing a fixed string, I pass a function that regenerates the OAuth token whenever the MCP session establishes a connection or refreshes its token. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK:
AI Agent (Google ADK) | | Structured MCP tool calls v
MCP Server (BigQuery) | v
BigQuery datasets Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
AI Agent (Google ADK) | | Structured MCP tool calls v
MCP Server (BigQuery) | v
BigQuery datasets CODE_BLOCK:
AI Agent (Google ADK) | | Structured MCP tool calls v
MCP Server (BigQuery) | v
BigQuery datasets COMMAND_BLOCK:
#clone my github repo:
git clone https://github.com/karthidec/google-adk-mcp-bigquery.git #authenticate with google cloud
gcloud config set project [YOUR-PROJECT-ID]
gcloud auth application-default login #enable bigquery mcp server in your google project
gcloud beta services mcp enable bigquery.googleapis.com --project=PROJECT_ID # Create virtual environment
python3 -m venv .venv # Activate virtual environment
source .venv/bin/activate # Install ADK
pip install google-adk # Navigate to the app directory
cd bq_mcp/ # Run the ADK web interface
adk web Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
#clone my github repo:
git clone https://github.com/karthidec/google-adk-mcp-bigquery.git #authenticate with google cloud
gcloud config set project [YOUR-PROJECT-ID]
gcloud auth application-default login #enable bigquery mcp server in your google project
gcloud beta services mcp enable bigquery.googleapis.com --project=PROJECT_ID # Create virtual environment
python3 -m venv .venv # Activate virtual environment
source .venv/bin/activate # Install ADK
pip install google-adk # Navigate to the app directory
cd bq_mcp/ # Run the ADK web interface
adk web COMMAND_BLOCK:
#clone my github repo:
git clone https://github.com/karthidec/google-adk-mcp-bigquery.git #authenticate with google cloud
gcloud config set project [YOUR-PROJECT-ID]
gcloud auth application-default login #enable bigquery mcp server in your google project
gcloud beta services mcp enable bigquery.googleapis.com --project=PROJECT_ID # Create virtual environment
python3 -m venv .venv # Activate virtual environment
source .venv/bin/activate # Install ADK
pip install google-adk # Navigate to the app directory
cd bq_mcp/ # Run the ADK web interface
adk web COMMAND_BLOCK:
import os
import dotenv
from pathlib import Path
from . import tools
from google.adk.agents import Agent # Load environment variables relative to this file
dotenv.load_dotenv(Path(__file__).parent / ".env") PROJECT_ID = os.getenv('GOOGLE_CLOUD_PROJECT', 'project_not_set') # Initialize the toolset
bigquery_toolset = tools.get_bigquery_mcp_toolset() # Define the Agent
root_agent = Agent( model='gemini-2.5-flash', # Leveraging a fast, reasoning-capable model name='root_agent', instruction=f""" Help the user answer questions by strategically combining insights from two sources: 1. **BigQuery toolset:** Access demographic (inc. foot traffic index), product pricing, and historical sales data in the mcp_bakery dataset. Do not use any other dataset. Run all query jobs from project id: {PROJECT_ID}. Give list of zipcodes or any general query user wants to know. """, tools=[bigquery_toolset]
) Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
import os
import dotenv
from pathlib import Path
from . import tools
from google.adk.agents import Agent # Load environment variables relative to this file
dotenv.load_dotenv(Path(__file__).parent / ".env") PROJECT_ID = os.getenv('GOOGLE_CLOUD_PROJECT', 'project_not_set') # Initialize the toolset
bigquery_toolset = tools.get_bigquery_mcp_toolset() # Define the Agent
root_agent = Agent( model='gemini-2.5-flash', # Leveraging a fast, reasoning-capable model name='root_agent', instruction=f""" Help the user answer questions by strategically combining insights from two sources: 1. **BigQuery toolset:** Access demographic (inc. foot traffic index), product pricing, and historical sales data in the mcp_bakery dataset. Do not use any other dataset. Run all query jobs from project id: {PROJECT_ID}. Give list of zipcodes or any general query user wants to know. """, tools=[bigquery_toolset]
) COMMAND_BLOCK:
import os
import dotenv
from pathlib import Path
from . import tools
from google.adk.agents import Agent # Load environment variables relative to this file
dotenv.load_dotenv(Path(__file__).parent / ".env") PROJECT_ID = os.getenv('GOOGLE_CLOUD_PROJECT', 'project_not_set') # Initialize the toolset
bigquery_toolset = tools.get_bigquery_mcp_toolset() # Define the Agent
root_agent = Agent( model='gemini-2.5-flash', # Leveraging a fast, reasoning-capable model name='root_agent', instruction=f""" Help the user answer questions by strategically combining insights from two sources: 1. **BigQuery toolset:** Access demographic (inc. foot traffic index), product pricing, and historical sales data in the mcp_bakery dataset. Do not use any other dataset. Run all query jobs from project id: {PROJECT_ID}. Give list of zipcodes or any general query user wants to know. """, tools=[bigquery_toolset]
) COMMAND_BLOCK:
import os
import dotenv
import google.auth
import google.auth.transport.requests
from pathlib import Path
from typing import Dict, Optional, Any # We use Any here to avoid strict dependency issues if ADK isn't fully typed in your env
try: from google.adk.agents.readonly_context import ReadonlyContext
except ImportError: ReadonlyContext = Any from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams # Robustly load .env from the script's directory
dotenv.load_dotenv(Path(__file__).parent / ".env") BIGQUERY_MCP_URL = "https://bigquery.googleapis.com/mcp" def get_auth_headers() -> Dict[str, str]: """ Generates fresh authentication headers. Crucial for long-running agents where tokens might expire. """ credentials, project_id = google.auth.default( scopes=["https://www.googleapis.com/auth/bigquery"] ) # Fallback if default auth doesn't pick up the project ID if not project_id: project_id = os.getenv("GOOGLE_CLOUD_PROJECT") # Force a token refresh to ensure validity auth_req = google.auth.transport.requests.Request() credentials.refresh(auth_req) oauth_token = credentials.token return { "Authorization": f"Bearer {oauth_token}", "x-goog-user-project": project_id if project_id else "", "Content-Type": "application/json" } def auth_header_provider(context: Optional[ReadonlyContext]) -> Dict[str, str]: """Callback function used by the MCP Client to inject headers.""" return get_auth_headers() def get_bigquery_mcp_toolset(): # Initial headers for the handshake initial_headers = get_auth_headers() # We use StreamableHTTPConnectionParams for efficient data transfer tools = MCPToolset( connection_params=StreamableHTTPConnectionParams( url=BIGQUERY_MCP_URL, headers=initial_headers ), # This provider is the secret sauce for handling token expiry header_provider=auth_header_provider ) return tools Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
import os
import dotenv
import google.auth
import google.auth.transport.requests
from pathlib import Path
from typing import Dict, Optional, Any # We use Any here to avoid strict dependency issues if ADK isn't fully typed in your env
try: from google.adk.agents.readonly_context import ReadonlyContext
except ImportError: ReadonlyContext = Any from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams # Robustly load .env from the script's directory
dotenv.load_dotenv(Path(__file__).parent / ".env") BIGQUERY_MCP_URL = "https://bigquery.googleapis.com/mcp" def get_auth_headers() -> Dict[str, str]: """ Generates fresh authentication headers. Crucial for long-running agents where tokens might expire. """ credentials, project_id = google.auth.default( scopes=["https://www.googleapis.com/auth/bigquery"] ) # Fallback if default auth doesn't pick up the project ID if not project_id: project_id = os.getenv("GOOGLE_CLOUD_PROJECT") # Force a token refresh to ensure validity auth_req = google.auth.transport.requests.Request() credentials.refresh(auth_req) oauth_token = credentials.token return { "Authorization": f"Bearer {oauth_token}", "x-goog-user-project": project_id if project_id else "", "Content-Type": "application/json" } def auth_header_provider(context: Optional[ReadonlyContext]) -> Dict[str, str]: """Callback function used by the MCP Client to inject headers.""" return get_auth_headers() def get_bigquery_mcp_toolset(): # Initial headers for the handshake initial_headers = get_auth_headers() # We use StreamableHTTPConnectionParams for efficient data transfer tools = MCPToolset( connection_params=StreamableHTTPConnectionParams( url=BIGQUERY_MCP_URL, headers=initial_headers ), # This provider is the secret sauce for handling token expiry header_provider=auth_header_provider ) return tools COMMAND_BLOCK:
import os
import dotenv
import google.auth
import google.auth.transport.requests
from pathlib import Path
from typing import Dict, Optional, Any # We use Any here to avoid strict dependency issues if ADK isn't fully typed in your env
try: from google.adk.agents.readonly_context import ReadonlyContext
except ImportError: ReadonlyContext = Any from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams # Robustly load .env from the script's directory
dotenv.load_dotenv(Path(__file__).parent / ".env") BIGQUERY_MCP_URL = "https://bigquery.googleapis.com/mcp" def get_auth_headers() -> Dict[str, str]: """ Generates fresh authentication headers. Crucial for long-running agents where tokens might expire. """ credentials, project_id = google.auth.default( scopes=["https://www.googleapis.com/auth/bigquery"] ) # Fallback if default auth doesn't pick up the project ID if not project_id: project_id = os.getenv("GOOGLE_CLOUD_PROJECT") # Force a token refresh to ensure validity auth_req = google.auth.transport.requests.Request() credentials.refresh(auth_req) oauth_token = credentials.token return { "Authorization": f"Bearer {oauth_token}", "x-goog-user-project": project_id if project_id else "", "Content-Type": "application/json" } def auth_header_provider(context: Optional[ReadonlyContext]) -> Dict[str, str]: """Callback function used by the MCP Client to inject headers.""" return get_auth_headers() def get_bigquery_mcp_toolset(): # Initial headers for the handshake initial_headers = get_auth_headers() # We use StreamableHTTPConnectionParams for efficient data transfer tools = MCPToolset( connection_params=StreamableHTTPConnectionParams( url=BIGQUERY_MCP_URL, headers=initial_headers ), # This provider is the secret sauce for handling token expiry header_provider=auth_header_provider ) return tools - Reason about operational, financial, or analytical questions
- Discover approved tools dynamically
- Access BigQuery through a governed, auditable interface
- Receive structured results suitable for reliable downstream reasoning - Access can be tightly scoped and governed
- Queries are executed only through approved interfaces
- Permissions remain centralized and auditable - Reasoning happens in the agent.
- Execution happens in BigQuery.
- MCP sits cleanly in between. - Agentic reasoning aligned with SRE decision workflows
- Tool-based execution instead of brittle SQL-in-prompt patterns
- Enterprise-grade governance and security
- A realistic path from PoC to production - FinOps assistants for cost visibility and optimization
- SRE copilots for reliability, incident analysis, and capacity planning
- Platform analytics agents with strict access controls
- Executive decision systems grounded in governed cloud data - MCP is foundational for governed, enterprise AI
- Google ADK aligns well with platform engineering practices
- BigQuery is a natural backend for SRE and FinOps intelligence
- Separation of reasoning and execution is non-negotiable - Google Agent Development Kit (ADK): A robust framework for building, testing, and deploying AI agents.
- Google Big Query Model Context Protocol (MCP): An open standard that acts like a "USB port" for AI. We specifically use the BigQuery MCP Server to connect our model to data without custom, brittle integrations.
how-totutorialguidedev.toaiserverpythondatabasegitgithub