GEMINI LABJP
PRO35 — July 17, the date reports had pointed to, has passed without an official Gemini 3.5 Pro announcement or model card. July 24 is being cited as the fallbackNB2LITE — Nano Banana 2 Lite, otherwise known as Gemini 3.1 Flash-Lite Image, arrives as the fastest of the family: roughly four seconds per image at $0.034 per thousandOMNI — Gemini Omni Flash enters public preview, generating video up to ten seconds long at $0.10 per second of outputEDIT — Omni Flash is built around conversational editing. Swap a character, relight a scene, or change the angle in plain language, and the original audio and video tracks stay intactSYNTHID — Both new models carry SynthID watermarking, so anything they produce can be checked for provenance from inside the Gemini appSHUTDOWN — The older image generation models are deprecated and switch off on August 17. Worth checking your migration windowPRO35 — July 17, the date reports had pointed to, has passed without an official Gemini 3.5 Pro announcement or model card. July 24 is being cited as the fallbackNB2LITE — Nano Banana 2 Lite, otherwise known as Gemini 3.1 Flash-Lite Image, arrives as the fastest of the family: roughly four seconds per image at $0.034 per thousandOMNI — Gemini Omni Flash enters public preview, generating video up to ten seconds long at $0.10 per second of outputEDIT — Omni Flash is built around conversational editing. Swap a character, relight a scene, or change the angle in plain language, and the original audio and video tracks stay intactSYNTHID — Both new models carry SynthID watermarking, so anything they produce can be checked for provenance from inside the Gemini appSHUTDOWN — The older image generation models are deprecated and switch off on August 17. Worth checking your migration window
Articles/Advanced
Advanced/2026-06-27Advanced

Don't Ingest Gemini Deep Research Reports Blindly — A Citation-Verification Acceptance Gate for MCP-Grounded Research

Now that Deep Research connects to MCP servers and File Search, you can ground research on your own data. This builds an acceptance gate that verifies, before any automated ingest, whether each citation resolves to a trusted source — with an allowlist, a grounding-coverage ratio, and categorized reject reasons, all in working code.

Gemini74Deep Research6MCP4File Search6Verification

Premium Article

In the June 27, 2026 update, the new Deep Research gained MCP-server connectivity and File Search support. What used to be a feature that broadly searched public information can now treat your own data stores and on-hand MCP tools as grounding. As an indie developer who runs a fair amount of automation solo, I genuinely welcomed this. It looks like I can have it research questions against my own documents and logs, then feed the result straight into a drafting pipeline.

But the first thing that made me pause, when I actually tried wiring it in, was a simple question: can I really ingest the returned report as-is? A Deep Research output is cited prose. Citations make it read as authoritative, but whether each citation actually resolves to a source I trust — versus an unknown external page or a reference that points at nothing — is impossible to tell by reading the text. In an unattended ingest path, when this check is missing, "plausible-but-poorly-grounded" text quietly accumulates.

This article implements an acceptance gate that sits just before automated ingestion. It has three stages: pull citations out as structure, check whether each resolves against an allowlist of trusted sources, and stop ingestion if the grounding-coverage ratio falls below a threshold. The gate's core is plain verification logic that does not depend on the exact shape of the external API, so it survives changes to the Deep Research SDK.

Where the naive ingest path goes wrong

When you connect Deep Research to MCP, its grounding can mix "documents in your own File Search store" and "the external web." The report body makes claims, and each claim carries citations. The problem is that citation provenance splits three ways. One is your trusted sources (File Search document IDs on the allowlist, or domains you've approved). The second is unknown external domains. The third is citations that, when you try to resolve them, lead to nothing real.

Unattended ingestion fails when the second and third slip in and you treat "has a citation" as "is trustworthy." The third kind is especially nasty: the citation is formally present, yet its media_id, page number, or URL does not resolve to an actual source. A human reviewer would notice "this source looks off," but automation lets it through.

So the gate should verify neither readability nor length, but exactly one thing: does each individual citation actually resolve to a trusted source? We aggregate that per claim and decide ingestion by the share that resolved — the grounding-coverage ratio.

Receive the report as structure

To verify by machine, you first have to lift citations out of prose into structure. When you call Deep Research via the Interactions API, you pass your MCP connector and File Search as tools and receive the output with grounding metadata included. Below is the request skeleton. Field names follow the June 2026 changelog; adjust them to your installed SDK version. The verification body in the following sections is pure logic, so even if this part shifts, the gate does not need to be rebuilt.

from google import genai
from google.genai import types
 
client = genai.Client()
 
# Skeleton: run Deep Research with "own data first"
# - pass your MCP server and File Search as grounding sources
op = client.interactions.create(
    model="gemini-flash-latest",  # 3.5 Flash GA; speed and cost help for survey work
    agent="deep-research",
    input="Summarize this month's auto-posting failure trends, grounded in our ops logs",
    tools=[
        types.Tool(file_search=types.FileSearch(
            file_search_store_names=["projects/me/locations/global/fileSearchStores/ops-logs"],
        )),
        types.Tool(mcp=types.McpConnector(
            server_url="https://mcp.example.internal/ops",
            allowed_tools=["search_runs", "get_run"],
        )),
    ],
    config=types.InteractionConfig(
        include_grounding_metadata=True,  # receive citations as structure
        background=True,                  # take long jobs over a webhook
    ),
)

The key here is include_grounding_metadata=True. Without it, citations arrive only as footnote-like phrases in the body, and machine verification becomes far harder. Once you have structured citations, the rest is straightforward data processing.

On the receiving side, normalize the report into an array of "claims" and "the citations attached to each claim." Citations carry different information depending on provenance, so flatten them into one shared shape.

from dataclasses import dataclass, field
 
@dataclass
class Citation:
    kind: str                       # "file_search" | "web" | "mcp"
    doc_id: str | None = None       # File Search document ID
    media_id: str | None = None     # media_id for visual citations
    page_numbers: list[int] = field(default_factory=list)
    url: str | None = None          # source URL for web / mcp
 
@dataclass
class Claim:
    text: str
    citations: list[Citation]
 
def normalize_report(grounding) -> list[Claim]:
    claims: list[Claim] = []
    for seg in grounding.segments:
        cites = []
        for c in seg.citations:
            cites.append(Citation(
                kind=c.source_type,
                doc_id=getattr(c, "document_id", None),
                media_id=getattr(c, "media_id", None),
                page_numbers=list(getattr(c, "page_numbers", []) or []),
                url=getattr(c, "uri", None),
            ))
        claims.append(Claim(text=seg.text, citations=cites))
    return claims

After normalize_report, the report becomes an easy-to-verify "list of claims and citations." From here on, we never touch the external API.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Receive Deep Research citations as structure and decide acceptance by whether each resolves to a trusted source
Allowlist resolution plus a grounding-coverage ratio for graceful rejection, and how to set the threshold from real data
Log reject reasons by category and review them nightly to keep unattended ingestion trustworthy
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Advanced2026-07-10
My ADK Assistant Quietly Forgot a Deadline — Catching Compaction Memory Loss With a Recall Probe
Compacting conversation history in Google ADK with Gemini lowers cost, but it also erodes what your assistant remembers — silently. Here is how I built a recall probe to measure that loss, compared three compaction strategies against the same ledger, and stopped trading memory for tokens.
Advanced2026-07-08
When Your Knowledge Base Shifts Mid-Run: Pinning File Search to an Execution Epoch for Consistent Agent Grounding
When a File Search store is updated while a Managed Agent is running, a single execution can mix old and new grounding. Borrowing MVCC ideas, pinning an execution epoch keeps one agent run's evidence consistent. Here is the design and implementation.
Advanced2026-07-08
One File Search Store for Many Apps: Splitting Retrieval With customMetadata and Chunk Config
Put several apps' FAQs in a single Gemini File Search store and metadataFilter can silently return empty grounding, or answers get split across chunk boundaries. Here is the customMetadata design, the AIP-160 filter-syntax trap, and measured chunkingConfig tuning.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →