In Part 1 of this series, we built and deployed doc-reviewer-101 — a web application using Google ADK, Gemini 3.8 Flash, Google Drive Picker, and the new Google Docs API Comments & Suggested Edits primitives.
In Part 2, we upgrade our reviewer into a live Hybrid Fact-Checker & Citation Agent.

But what do we mean by that? Let’s understand that first.
Introduction: When simple Proofreading is not Enough
In Part 1, we solved a classic collaboration problem: instead of copying paragraphs into a chat window or letting a script overwrite a Google Doc, we built an AI agent that leaves native Suggested Edits (writeControl: {"writeMode": "SUGGEST"}) for typos and grammar, alongside Anchored Margin Comments (insertComment) for high-level feedback.
But when engineers, product managers, or technical writers review a real document, like an architecture design doc (RFC), a customer migration proposal, or a technical tutorial, highlighting spelling mistakes only is the not that important (though I wouldn’t discount it). The most important mistakes to catch if you are an expert reviewer is factual errors and outdated technical claims. Let’s see a few examples:
- “Cloud Run services only support a maximum request timeout of 15 minutes and 8 GiB of RAM.” (Outdated: Cloud Run supports up to 60 minutes and 32 GiB of RAM).
- “Run gcloud run deploy my-api –source . –public-access to expose the service." (Hallucinated CLI flag: the real flag is –allow-unauthenticated).
- “We are standardizing on Python 3.12, released in October 2021.” (Wrong date: Python 3.12 was released in October 2023).
If an AI reviewer relies only on its static pre-training memory, it will either miss outdated quotas or hallucinate corrections of its own. And even if an AI does suggest changing 15 minutes to 60 minutes, no author will click ✓ Accept unless they can see where that number came from.
In Part 2, we upgrade doc-reviewer-101 so that whenever it reviews a Google Doc, it:
- Verifies Google developer & cloud claims against official documentation using the Google Developer Knowledge Remote MCP Server (https://developerknowledge.googleapis.com/mcp).
- Verifies general public facts, dates, and industry statistics using Google Search Grounding (google_search) wrapped in ADK's AgentTool pattern.
- Proposes the corrected fact or CLI flag inline as a Suggested Edit (writeMode: "SUGGEST").
- Attaches the verified source URL and explanation right next to it as an Anchored Margin Comment (insertComment).
A sample run is shown below:

Architecture: Why Combine Developer Knowledge MCP with Google Search Grounding?
When fact-checking a technical or business document, a single search source is rarely ideal for every claim:
- Why General Web Search Alone Falls Short on Cloud/Developer Specs: If your document mentions a Google Cloud quota, gcloud CLI flag, IAM permission, or ADK API, searching the open web can surface outdated 2021 blog posts or old StackOverflow answers.
- Why Official Docs Alone Fall Short on General Facts: If your document mentions Python release dates, industry adoption statistics, or third-party benchmarks, those don’t live inside Google’s product documentation.
By combining both inside our Google Agent Development Kit (ADK) application, the agent routes each claim to the most authoritative source:
+-------------------------------------------------------------------------+
| ADK ROOT AGENT (doc_reviewer_101) |
| 1. Calls read_google_doc(document_id) |
| 2. Identifies verifiable claims in the text |
+-------------------+---------------------------------+-------------------+
| |
Google Cloud / | | General Web /
Gemini / ADK / | | Industry Stats /
Firebase / Go v v Release Dates
+-----------------------------------+ +-----------------------------------+
| ENGINE 1: DEVELOPER KNOWLEDGE MCP | | ENGINE 2: GOOGLE SEARCH SUB-AGENT |
| https://developerknowledge | | Wrapped via ADK AgentTool() |
| .googleapis.com/mcp | | |
| | | - Uses built-in google_search |
| Exposed MCP Tools: | | - Verifies public facts, dates, |
| - answer_query | | and non-Google claims |
| - search_documents | | - Returns verdict + source URL |
| - get_documents | | |
+-----------------+-----------------+ +-----------------+-----------------+
| |
+------------------+------------------+
|
v
+-------------------------------------------------------------------------+
| COORDINATED GOOGLE DOCS API UPDATES |
| |
| Step 3: insert_comments FIRST |
| -> Anchors the verified URL & explanation in the margin |
| |
| Step 4: propose_suggested_edits SECOND (sorted back-to-front) |
| -> Crosses out outdated fact/flag & suggests the exact fix |
+-------------------------------------------------------------------------+
Connecting to the Google Developer Knowledge Remote MCP Server
Google provides an official remote Model Context Protocol (MCP) server for developer documentation at https://developerknowledge.googleapis.com/mcp.
It indexes official documentation across:
- Google Cloud (cloud.google.com, docs.cloud.google.com)
- Google AI & Gemini (ai.google.dev, adk.dev, genkit.dev)
- Firebase, Android, Chrome, Flutter, Dart, Go, and Web.dev
When connected via ADK’s McpToolset, the server automatically exposes three tools to your agent:
- answer_query: Performs server-side RAG over official Google documentation and returns a synthesized answer with canonical document references.
- search_documents: Searches document chunks for exact CLI flags, API parameters, and IAM roles.
- get_documents: Retrieves the full markdown content of specific documentation pages.
Important ADK Nuance: Startup vs. Runtime Auth Headers in McpToolset
In our FastAPI application (app/fast_api_app.py), ADK builds an A2A Agent Card during server startup (attach_a2a_routes). During startup, ADK calls developer_knowledge_mcp.get_tools(readonly_context=None) to inspect the MCP server's tool schemas before any user request exists.
In google-adk, McpToolset's header_provider callback is only invoked when readonly_context is non-null (i.e., during an active agent turn). Therefore, to ensure https://developerknowledge.googleapis.com/mcp authenticates cleanly both at FastAPI startup and on every runtime turn, we pass _developer_knowledge_headers() to StreamableHTTPConnectionParams(headers=…) and to McpToolset(header_provider=…):
import os
from typing import Optional
import google.auth
import google.auth.transport.requests
from google.adk.agents.readonly_context import ReadonlyContext
from google.adk.tools.mcp_tool.mcp_toolset import (
McpToolset,
StreamableHTTPConnectionParams,
)
def _developer_knowledge_headers(
readonly_context: Optional[ReadonlyContext] = None,
) -> dict[str, str]:
"""Builds auth headers for https://developerknowledge.googleapis.com/mcp."""
api_key = os.getenv("DEVELOPERKNOWLEDGE_API_KEY", "").strip()
if api_key:
return {"X-Goog-Api-Key": api_key}
creds, project_id = google.auth.default(
scopes=["https://www.googleapis.com/auth/cloud-platform"]
)
if not creds.valid:
creds.refresh(google.auth.transport.requests.Request())
quota_project = os.getenv("GOOGLE_CLOUD_PROJECT") or project_id or ""
headers = {"Authorization": f"Bearer {creds.token}"}
if quota_project:
headers["X-Goog-User-Project"] = quota_project
return headers
developer_knowledge_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(
url="https://developerknowledge.googleapis.com/mcp",
headers=_developer_knowledge_headers(),
timeout=30.0,
sse_read_timeout=30.0,
),
header_provider=_developer_knowledge_headers,
)
Notice how zero extra API keys are needed: _developer_knowledge_headers automatically uses your backend Application Default Credentials (google.auth.default) and attaches your GOOGLE_CLOUD_PROJECT in the X-Goog-User-Project header!
Adding Google Search Grounding via ADK’s AgentTool Pattern
For general claims outside of Google’s developer documentation, we want our agent to use Gemini’s built-in Google Search Grounding (google_search).
However, there is a critical Gemini API rule every ADK developer needs to know:
In Gemini, google_search is a model-internal grounding tool. It cannot be mixed directly in the same tools=[…] list alongside custom FunctionTools (like read_google_doc, insert_comments, propose_suggested_edits) or McpToolset's on a single Agent.
How do we combine google_search with custom tools and MCP servers? We use ADK's AgentTool pattern:
- We create a focused sub-agent (web_search_verifier) whose only tool is google_search.
- We wrap web_search_verifier in AgentTool(web_search_verifier) and give that AgentTool to our root doc_reviewer_101 agent!
from google.adk.agents import Agent
from google.adk.tools import AgentTool, google_search
web_search_verifier = Agent(
name="web_search_verifier",
model="gemini-3.8-flash",
description=(
"Verifies general public facts, industry statistics, release dates, "
"and non-Google technical claims using Google Search Grounding."
),
instruction=(
"You are a precise fact-checking researcher. Given a factual claim from a document:\n"
"1. Use `google_search` to verify whether the claim is accurate and up to date.\n"
"2. Return the verdict (Accurate, Outdated/Incorrect, or Unverifiable), "
"the exact corrected value/fact if inaccurate, and the authoritative source URL."
),
tools=[google_search],
)
To the root doc_reviewer_101 agent, web_search_verifier looks just like any other callable function tool, while inside web_search_verifier, Gemini executes native Google Search Grounding in its own isolated model call!
The Complete Upgraded app/agent.py
Putting both verification engines together with our Google Docs API tools (read_google_doc, insert_comments, and propose_suggested_edits), here is our complete Part 2 app/agent.py:
# app/agent.py
import os
from typing import Optional
import google.auth
import google.auth.transport.requests
from dotenv import load_dotenv
from google.adk.agents import Agent
from google.adk.agents.callback_context import CallbackContext
from google.adk.agents.readonly_context import ReadonlyContext
from google.adk.apps import App
from google.adk.tools import AgentTool, google_search
from google.adk.tools.mcp_tool.mcp_toolset import (
McpToolset,
StreamableHTTPConnectionParams,
)
from app.tools import insert_comments, propose_suggested_edits, read_google_doc
load_dotenv()
DEFAULT_SUGGESTED_EDITS_CRITERIA = (
"- Outdated or inaccurate technical numbers, quotas, CLI flags, or dates verified via Developer Knowledge or Google Search.\n"
"- Spelling mistakes and typos.\n"
"- Grammatical errors (such as subject-verb disagreement, tense errors, or punctuation).\n"
"- Awkward or redundant word choices."
)
DEFAULT_COMMENTS_CRITERIA = (
"- Factual claims, quotas, CLI commands, or statistics that were verified or corrected (attach the authoritative source URL and brief explanation in the comment).\n"
"- Exaggerated or unverified claims that lack citations or benchmark data.\n"
"- Unrealistic timelines or vague action items that need clear owners or dates."
)
def ensure_review_criteria_defaults(callback_context: CallbackContext):
"""Populates default review templates in session state if the user didn't override them."""
if not callback_context.state.get("suggested_edits_criteria"):
callback_context.state["suggested_edits_criteria"] = (
DEFAULT_SUGGESTED_EDITS_CRITERIA
)
if not callback_context.state.get("comments_criteria"):
callback_context.state["comments_criteria"] = DEFAULT_COMMENTS_CRITERIA
return None
def _developer_knowledge_headers(
readonly_context: Optional[ReadonlyContext] = None,
) -> dict[str, str]:
"""Builds auth headers for https://developerknowledge.googleapis.com/mcp."""
api_key = os.getenv("DEVELOPERKNOWLEDGE_API_KEY", "").strip()
if api_key:
return {"X-Goog-Api-Key": api_key}
creds, project_id = google.auth.default(
scopes=["https://www.googleapis.com/auth/cloud-platform"]
)
if not creds.valid:
creds.refresh(google.auth.transport.requests.Request())
quota_project = os.getenv("GOOGLE_CLOUD_PROJECT") or project_id or ""
headers = {"Authorization": f"Bearer {creds.token}"}
if quota_project:
headers["X-Goog-User-Project"] = quota_project
return headers
developer_knowledge_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(
url="https://developerknowledge.googleapis.com/mcp",
headers=_developer_knowledge_headers(),
timeout=30.0,
sse_read_timeout=30.0,
),
header_provider=_developer_knowledge_headers,
)
web_search_verifier = Agent(
name="web_search_verifier",
model="gemini-3.8-flash",
description=(
"Verifies general public facts, industry statistics, release dates, "
"and non-Google technical claims using Google Search Grounding."
),
instruction=(
"You are a precise fact-checking researcher. Given a factual claim from a document:\n"
"1. Use `google_search` to verify whether the claim is accurate and up to date.\n"
"2. Return the verdict (Accurate, Outdated/Incorrect, or Unverifiable), "
"the exact corrected value/fact if inaccurate, and the authoritative source URL."
),
tools=[google_search],
)
INSTRUCTION = """
You are an AI Document Reviewer and Fact-Checker for Google Docs.
When given a Google Document ID, execute these steps in exact order:
1. READ:
Call `read_google_doc` to retrieve the document's text.
2. FACT-CHECK & VERIFY CLAIMS:
Identify verifiable technical claims, quotas, CLI commands, release dates, or statistics in the document:
- For Google Cloud (Cloud Run, GKE, BigQuery, Vertex AI, IAM), Gemini, ADK, Firebase, Android, Chrome, Flutter, or Go claims:
Use the Developer Knowledge MCP tools (`answer_query` or `search_documents`) to verify against official Google documentation.
- For general world facts, industry statistics, release dates, or non-Google claims:
Call `web_search_verifier` to verify using Google Search.
3. COMMENT FIRST (Based on User's Comment Criteria & Fact-Check Citations):
Review the document against these Comment Criteria:
{comments_criteria}
Call `insert_comments` FIRST with the exact `target_text` from the document and helpful `comment_text`.
Whenever you verified or corrected a factual claim in Step 2, include the authoritative source URL and explanation in `comment_text`.
4. SUGGEST EDITS SECOND (Based on User's Suggested Edits Criteria & Fact Corrections):
Review the document against these Suggested Edits Criteria:
{suggested_edits_criteria}
Call `propose_suggested_edits` SECOND with each exact `target_text` and its `replacement_text` (including factual corrections found in Step 2 as well as grammar/typo fixes).
Include 1-2 surrounding words in `target_text` if a typo or number is short to ensure unique matching.
5. SUMMARIZE:
Return a clear summary of all fact-checks, citations, comments, and suggested edits applied, and provide the link:
https://docs.google.com/document/d/<DOCUMENT_ID>/edit
"""
root_agent = Agent(
name="doc_reviewer_101",
model="gemini-3.8-flash",
description="Reviews and fact-checks a Google Doc using Developer Knowledge MCP and Google Search Grounding, then adds comments and suggested edits.",
instruction=INSTRUCTION,
tools=[
read_google_doc,
developer_knowledge_mcp,
AgentTool(web_search_verifier),
insert_comments,
propose_suggested_edits,
],
before_agent_callback=ensure_review_criteria_defaults,
)
app = App(root_agent=root_agent, name="app")
We also add "mcp>=1.8.0" to dependencies in pyproject.toml so ADK's McpToolset has the MCP client SDK installed.
Step-by-Step: Testing the Hybrid Fact-Checker
Step 1: Enable the Developer Knowledge API
Enable developerknowledge.googleapis.com in your Google Cloud project:
export PROJECT_ID="your-gcp-project-id"
gcloud services enable developerknowledge.googleapis.com --project="${PROJECT_ID}"
Step 2: Sync Dependencies & Start the Server
From your doc-reviewer-101 directory:
uv sync
uv run uvicorn app.fast_api_app:app --reload --port 8000
Step 3: Create a Sample Test Google Doc with Deliberate Myths & Errors
Create a new Google Doc in your Google Drive and paste the following two paragraphs:
Project Proposal: Migrating Our Analytics API to Google Cloud Run
Our engineering team plans to migrate our Python backend to Google Cloud Run next month. Currently, our batch jobs take 25 minutes to complete, which is a problem because Cloud Run services only support a maximum request timeout of 15 minutes and a maximum memory limit of 8 GiB per instance. To deploy the container publicly from source, engineers will run gcloud run deploy my-api --source . --public-access.
For runtime language support, we are standardizing on Python 3.12, which was officially released in October 2021. We beleive this migration will immediatly reduce our monthly infrastructure bill by 95% within the first week without requiring any load testing.
Step 4: Run the Review and Inspect the Results
Open http://localhost:8000/reviewer, sign in with Google, pick your test Google Doc via Browse Google Drive, and click Run AI Review.
When you open the reviewed Google Doc, you will see how the two verification engines and the two Google Docs API primitives work in tandem:
- Google Cloud Quotas Verified via Developer Knowledge MCP:
- Inline Suggested Edit: Crosses out 15 minutes and 8 GiB and suggests 60 minutes and 32 GiB.
- Anchored Margin Comment: Attaches the official docs.cloud.google.com/run/docs/configuring/request-timeout and memory limits citation URLs.
2. CLI Flag Verified via Developer Knowledge MCP:
- Inline Suggested Edit: Crosses out –public-access and suggests –allow-unauthenticated.
- Anchored Margin Comment: Explains that –allow-unauthenticated is the valid gcloud run deploy flag for public HTTP access.
3. Release Date Verified via Google Search Grounding (AgentTool):
- Inline Suggested Edit: Crosses out October 2021 and suggests October 2023.
- Anchored Margin Comment: Cites the official Python 3.12 release date (October 2, 2023).
4. Prose & Editorial Review:
- Inline Suggested Edits: Fixes beleive → believe and immediatly → immediately.
- Anchored Margin Comment: Flags the unverified “reduce our monthly infrastructure bill by 95%” claim.
Conclusion
By pairing the Google Docs Comments & Suggested Edits API with Google Developer Knowledge MCP and Google Search Grounding in ADK, we transform our reviewer from a simple grammar checker into a trustworthy technical co-editor:
- Suggested Edits save the author time by proposing the exact corrected numbers, CLI flags, and prose inline.
- Anchored Comments build trust by attaching the exact documentation link or search citation right next to the edit.
Check out the complete updated repository at github.com/rominirani/doc-reviewer-101.
Grounding Google Docs Suggested Edits with Developer Knowledge MCP and Google Search was originally published in Google Cloud – Community on Medium, where people are continuing the conversation by highlighting and responding to this story.
Source Credit: https://medium.com/google-cloud/grounding-google-docs-suggested-edits-with-developer-knowledge-mcp-and-google-search-9e2a3bf2800e?source=rss—-e52cf94d98af—4
