# Google BigQuery — MCP: Governing BigQuery from an AI Agent over MCP

*The same import–audit–generate loop, driven by tool calls instead of curl - including how agents ship multi-megabyte extracts.*

# Governing BigQuery from an AI Agent over MCP

*The same import–audit–generate loop, driven by tool calls instead of curl - including how agents ship multi-megabyte extracts.*

"Has anything drifted in the analytics dataset since we last agreed the model?" is a question an AI agent can now answer directly, with evidence. CoreModels (by ARAMAI) exposes its vendor-integration verbs as MCP tools, so any MCP-capable agent - Claude, Claude Code, or anything speaking streamable HTTP - can check a BigQuery estate against its governed model, import a new estate, and generate governed DDL, all under the same role checks a human user faces. This article walks the four tools that matter for BigQuery and the arguments they actually take.

## Connecting

CoreModels serves two MCP endpoints. `/mcp` is the public endpoint: read-only tools only, which for integrations means audit, generate, and status. `/mcp-admin` additionally serves the write tools, including vendor import. Both use OAuth 2.0 with dynamic client registration and PKCE - an unauthenticated request gets a 401 pointing at the resource metadata, and spec-compliant clients complete the flow automatically. From Claude Code:

```bash
claude mcp add --transport http coremodels https://coremodels.example.com/mcp
```

and, when the agent should be able to import:

```bash
claude mcp add --transport http coremodels-admin https://coremodels.example.com/mcp-admin
```

The endpoint split is convenience, not the security boundary. The enforced boundary is the per-project role check: write tools require Editor or Admin membership on the target project regardless of which endpoint the token came through.

## Discovery: `get_vendor_integration_status`

An agent should never hard-code what connectors exist. Called with just a project id, this tool lists every registered connector with capabilities and expected artifacts:

```json
{ "graphProjectId": "3f2a9c81d4b6470e8a1c5d9e2b7f4a63" }
```

The BigQuery entry reports key `bigquery`, display name `Google BigQuery`, capabilities `Import, Audit, Generate`, and one required artifact, `information_schema`, with a note describing what it is. Add the `vendor` argument and the tool switches to project status:

```json
{ "graphProjectId": "3f2a9c81d4b6470e8a1c5d9e2b7f4a63", "vendor": "bigquery" }
```

Now it returns whether an import has happened, the last-import state (timestamps, fingerprint, counts), and how many governed datasets currently resolve in the graph. This is the agent's orientation move: one call tells it whether there is anything to audit yet.

## The audit: `audit_vendor_project`

The workhorse. It compares fresh BigQuery artifacts against the governed graph and reports coverage, drift, and conformance - read-only, Viewer role, available on both endpoints. Required arguments are `graphProjectId` (32-char hex) and `vendor`; the artifacts come either inline or by URL:

```json
{
  "graphProjectId": "3f2a9c81d4b6470e8a1c5d9e2b7f4a63",
  "vendor": "bigquery",
  "artifacts": {
    "information_schema": "<the JSON rows exported by the documented extraction query>"
  }
}
```

The result carries the error/warning/info counts, the individual findings - each with section, severity, a stable kebab-case code such as `field-type-drift` or `semi-structured-column`, subject, message, and detail - plus a `markdown` report ready to paste into a pull request or a chat reply. The contract an agent should internalize: `errorCount > 0` means governed meaning is violated; warnings and infos are advisory. An optional `spaces` array scopes the audit to specific space ids.

## Large extracts: the `artifactUrls` flow

A real estate extract can be far bigger than an agent wants to inline in a tool call. Both artifact-bearing tools therefore accept `artifactUrls` - artifact name to URL - and CoreModels fetches the content server-side:

```json
{
  "graphProjectId": "3f2a9c81d4b6470e8a1c5d9e2b7f4a63",
  "vendor": "bigquery",
  "artifactUrls": {
    "information_schema": "https://artifacts.example.com/extracts/information_schema.json"
  }
}
```

Because these are server-side GETs to caller-supplied URLs, the fetch is deliberately locked down: HTTPS only, redirects disabled, hosts resolving to loopback, link-local, or private ranges refused, a 60-second timeout, and a hard response-size cap of 256 MB. Anything refused or failed does not silently vanish - it comes back in the tool result's fetch-problems list, and you can mix `artifacts` and `artifactUrls` in one call. The practical pattern: a pipeline drops the fresh extract onto object storage with a short-lived HTTPS URL, and the agent passes the URL instead of the payload.

## The import: `import_vendor_project`

Import is the one verb in this loop that writes, so it requires the Admin role and is served on `/mcp-admin` only. The arguments are the same shape as the audit - `graphProjectId`, `vendor`, and `artifacts` and/or `artifactUrls`:

```json
{
  "graphProjectId": "3f2a9c81d4b6470e8a1c5d9e2b7f4a63",
  "vendor": "bigquery",
  "artifactUrls": {
    "information_schema": "https://artifacts.example.com/extracts/information_schema.json"
  }
}
```

The semantics matter more than the mechanics: import is **additive**. Datasets become governed Types, columns become Elements with their native BigQuery types preserved as vendor metadata, `is_nullable = NO` becomes a NotNull check - but already-governed nodes are never mutated. An agent re-importing a grown estate adds the new tables and touches nothing else; the result reports how many datasets were added versus skipped as already existing, plus a lossiness list for everything honestly approximated (BigQuery's `STRUCT`/`ARRAY`/`JSON` columns, for instance, are governed as String because the flat extract cannot see their inner schemas). When the agent wants to know what *changed* rather than what is new, the answer is not re-import - it is `audit_vendor_project`.

## Closing the loop: `generate_vendor_artifacts`

BigQuery has the Generate capability, so an agent can also emit governance back toward the warehouse:

```json
{
  "graphProjectId": "3f2a9c81d4b6470e8a1c5d9e2b7f4a63",
  "vendor": "bigquery",
  "typeNames": ["orders", "customers"]
}
```

`typeNames` is optional - empty means every eligible governed type. The tool returns one artifact, `coremodels_bigquery_tables.sql`: `CREATE TABLE IF NOT EXISTS` DDL with `NOT NULL` from governed checks and `OPTIONS(description=...)` on both columns and tables - with governed allowed-value lists and references written into the column descriptions. Read-only like the audit - the tool hands the SQL to the agent; applying it in BigQuery remains a human-owned act, ideally via the same review process as any other DDL change.

## What an agent session actually looks like

A governance check-in composes naturally from these pieces. The agent calls `get_vendor_integration_status` with `vendor: "bigquery"` to confirm the estate is imported and when it last changed. It asks the pipeline for a fresh extract URL and calls `audit_vendor_project` with `artifactUrls`. If `errorCount` is zero it reports the warning-level story - perhaps three undocumented tables and one `STRUCT` column worth governing explicitly. If not, it pastes the `markdown` report, names the drifted objects, and proposes the two legitimate resolutions: change the estate back, or change the governed model deliberately and let `generate_vendor_artifacts` express the new agreement as DDL.

Two honest boundaries to plan around. First, the drift-trail verbs - reaudit, history, and the SVG badge - live on the HTTP surfaces, not MCP; an agent that wants a fresh verdict simply runs `audit_vendor_project` again with fresh artifacts, which is the same engine the reaudit verb uses. Second, nothing here ever touches Google credentials: the agent audits what was extracted and uploaded, which is exactly why a read-only agent on `/mcp` can be given this power without a security review of your GCP estate.

For the extraction query that produces the `information_schema` artifact and the full HTTP equivalents of every call above, see the Google BigQuery quickstart in the CoreModels documentation.
