Gemini Deep Research API with a remote MCP server: social data you can check
The Gemini Deep Research API accepts remote MCP servers but not custom functions. 7 live social data calls cost $0.0046. Setup, pricing, citation checks.

The short answer is yes. The Gemini Deep Research API can call a remote MCP server today. It cannot take custom function declarations, and it does not support structured output. All three facts are in the "Limitations" section of Google's Deep Research page (Deep Research docs, updated 2026-10-13). So you can point it at the EveryInfra remote MCP server at https://api.everyinfra.com/mcp.
We also made 7 live calls to our social and news data API on 2026-11-02, between 00:16 and 00:20 SGT. They returned 131 rows and cost $0.0046 in total. The data showed that the model is not the weak point for checkable citations. The weak point is the data itself. English news dates were 0 to 1 day late, and all 10 Spanish news dates were empty. None of 50 YouTube comments had a link, while all 35 Reddit comments had a permalink.
This article answers one practical question. You want Gemini Deep Research to write a report on a public topic. You also want every claim about social media in that report to point to a row that a reader can open. How do you give the agent structured social data so that this works?
We picked e-bike battery fires in New York City as the test topic. A fire in a Bronx apartment on 2026-10-28 killed a boy and later three more people. It produced English and Spanish news, Reddit threads and YouTube videos within days, so it is a good test of four source types.
Every fact about Google in this article comes from pages on ai.google.dev, Google Cloud docs or the Google blog. We have no Gemini API key, and we did not run Deep Research. All Gemini code below is a configuration example, not a test result. Every EveryInfra number comes from the raw responses of our live calls.

Can the Gemini Deep Research API connect to a remote MCP server?
Yes. The Deep Research page lists five tool types. Three of them are on by default: google_search, url_context and code_execution. Two more need to be added: mcp_server and file_search (Deep Research docs, "Supported tools"). This feature shipped on 2026-04-21 with the new Deep Research agents. The changelog entry mentions collaborative planning, visualization, MCP server integration and File Search (Gemini API changelog).
The mcp_server tool has five fields. type is required and must be "mcp_server". name is a display name, and url is the full URL of the MCP endpoint. headers holds HTTP headers that go with every request, and the docs give an auth token as the example. allowed_tools limits which tools on that server the agent can call.
Custom functions are a different matter. The first limitation on the same page says that you cannot currently give Deep Research custom Function Calling tools. It adds that you can use remote MCP servers instead. The second limitation is that structured output is not supported. The third is a maximum research time of 60 minutes, and most tasks should finish within 20 minutes.
Two other sentences on Google's pages can confuse readers. The Google blog post for Deep Research Max says that Deep Research "supports arbitrary tool definitions" (Google blog, 2026-04-21). Read next to the docs, this means tools exposed through MCP, not function declarations in the request. The Interactions API overview also says that Gemini 3 does not support remote MCP yet (Interactions API overview, updated 2026-10-15). That note is about models called with the model parameter. Deep Research is an agent called with the agent parameter, so the note does not apply to it.
| Question | Answer in Google's docs | Source and date |
|---|---|---|
| Remote MCP server? | Yes, tool type mcp_server with headers and allowed_tools | Deep Research docs, 2026-10-13 |
| Custom functions? | No, not currently | Same page, Limitations |
| Structured JSON output? | No | Same page, Limitations |
| Maximum run time? | 60 minutes, most within 20 | Same page, Limitations |
| Background mode required? | Yes, background=true with store=true | Same page, background docs |
| Context and output limits | 1,048,576 input and 65,536 output tokens | Model page, 2026-10-29 |
| Agent names | deep-research-preview-04-2026, deep-research-max-preview-04-2026 | Model page, changelog |

So both routes in our plan work, but their order changes. In route A, you put our MCP URL in tools. The agent then decides by itself when to search Reddit or pull news during the run. In route B, your program calls POST /api/v1/social first. It turns the results into a table and gives that table to the agent as input or as File Search documents.
Route B is not required, but it is the safer route for checkable citations. The reason is in the data, not in Gemini.
How the Gemini Deep Research API call works: background mode, polling and streaming
Deep Research runs only through the Interactions API, not through the older generateContent method. The Interactions API launched on 2025-12-11 and became generally available in June 2026. Google now calls it the default interface for new projects (Interactions API overview).
A Deep Research call differs from a normal model call in three ways. You use the agent parameter, not model. You must set background=true, and the API returns a partial object with an id at once. Then you poll with that id or open a stream.
The block below follows the REST example in the docs. It is a configuration example that we did not run.
# Configuration example: start Deep Research with the EveryInfra remote MCP server (not run by us)
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{
"agent": "deep-research-preview-04-2026",
"input": "Research how e-bike battery fires in New York City were discussed in news, Reddit and YouTube in October 2026. For every claim about social media, quote the row id and url from the EveryInfra tool result. If a date is approximate, say so.",
"tools": [
{"type": "google_search"},
{"type": "url_context"},
{"type": "mcp_server",
"name": "EveryInfra",
"url": "https://api.everyinfra.com/mcp",
"headers": {"Authorization": "Bearer '"$EVERYINFRA_API_KEY"'"},
"allowed_tools": ["everyinfra_list_capabilities", "everyinfra_call_api", "everyinfra_get_job"]}
],
"agent_config": {"type": "deep-research", "thinking_summaries": "auto"},
"background": true
}'
# Poll (replace INTERACTION_ID with the id from the first response)
curl "https://generativelanguage.googleapis.com/v1beta/interactions/INTERACTION_ID" \
-H "x-goog-api-key: $GEMINI_API_KEY"A background interaction has five states: in_progress, requires_action, completed, failed and cancelled (background execution docs). background=true needs store=true, and store=false with background mode returns a 400 error. Stored interactions stay for 55 days on the paid tier and 1 day on the free tier. Paid projects can change this to 7, 14 or 28 days in AI Studio. This matters for data. Your EveryInfra key in headers does not appear in the interaction, but every social data row that the agent pulls is stored as a step.
Streaming needs both stream=true and background=true. To see thought summaries during the run, also set agent_config.thinking_summaries to "auto". The example in the docs handles a dropped connection. It saves the interaction_id and the last event_id. After a drop, it calls GET /interactions/{id}?stream=true&last_event_id=... to resume. The docs name a 600-second timeout as one cause of drops, so this reconnect logic is not optional for a long run.
| `agent_config` field | Default | What it does | Why it matters here |
|---|---|---|---|
type | Required, "deep-research" | Marks a Deep Research call | — |
thinking_summaries | "none" | "auto" shows steps in the stream | You can see when the agent calls MCP |
visualization | "auto" | Allows charts, but draws them only when the prompt asks | Ask for charts in the prompt |
collaborative_planning | false | Returns a plan first; edit it with previous_interaction_id, then set false on the last turn. A reply like "looks good" without the switch change gives no report (Philipp Schmid, 2026-04-29) | Limit the capabilities at plan time |
Gemini Deep Research API pricing: $1 to $3 per task, $3 to $7 for Max
Google does not give Deep Research its own price. You pay for model inference and tool use separately (pricing page, "Pricing for agents", updated 2026-10-30). All inference is billed at standard Gemini rates, and this includes the intermediate tokens in the agent loop. Tools are billed at their own rates. Google Search results do not count as tokens, but content from URL Context and File Search does.
The Deep Research page gives a cost estimate (Deep Research docs, "Estimated costs"). A standard task with moderate analysis uses about 80 searches and 250,000 input tokens, with 50% to 70% cached. It also uses about 60,000 output tokens, for a total of about $1 to $3. A Max task for deep competitive analysis uses up to about 160 searches, 900,000 input tokens and 80,000 output tokens. Its estimate is about $3 to $7.
The pricing page also lists Google Search prices. Gemini 3 and later models share 5,000 free searches per month. After that, searches cost $14 per 1,000, and each project has a default cap of 1,500 searches per day. The docs do not say whether searches inside Deep Research are billed at this price or count toward the daily cap. If they do count, the cap allows about 18 reports a day at 80 searches each. We did not run Deep Research, so check the usage in your own bill.
Spend limits are easy to miss. The rate limit page says that the Gemini API also limits spend in a rolling 10-minute window. The limit is $10 on Tier 1, $50 on Tier 2 and $200 on Tier 3. A project over the limit gets 429 RESOURCE_EXHAUSTED (rate limits, updated 2026-10-28). At $3 per task, a Tier 1 project can hit the limit with three or four tasks in 10 minutes.
The paid tier also has an entry step. The billing page says that you link a billing account to move from the free tier to the paid tier. New accounts get the prepay plan by default, with a minimum top-up of $5 (billing docs). Requests fail when the prepaid balance runs out. For a project that runs scheduled reports, keep enough balance or turn on automatic top-ups.
Teams with many reports can look at Google Cloud. The Deep Research page for Google Cloud describes a service_tier="deferred" option when stream=false. It moves background tasks to off-peak hours at half price (Google Cloud Deep Research docs).
| Cost item | Price (read on 2026-11-02) | Use in one Deep Research task |
|---|---|---|
| Model inference | Standard Gemini rates, incl. intermediate tokens | About 250k in, 60k out (Max 900k, 80k) |
| Google Search | 5,000 free per month, then $14 per 1,000, 1,500 per day cap | About 80 searches (Max about 160) |
| URL Context | Content billed as input tokens | Depends on pages read |
| File Search | Indexing at $0.15 per 1M embedding tokens; storage and query embeddings free | Only when you upload files |
| Code execution | Code and results billed as tokens | When the agent computes or charts |
| EveryInfra social data | Catalog price_usd per call; no charge for failures or empty results | 23 calls for one report, about $0.0135 |
The social data part of the bill is small. At catalog prices on 2026-11-02, google_news/search costs $0.000792 per call. reddit/search, reddit/comments, youtube/search and youtube/comments cost $0.000556 per call. Each call has one price, whatever the number of rows. Suppose one report uses 3 news searches, 3 Reddit searches, comments from 10 Reddit threads, 2 YouTube searches and comments from 5 videos. That is 23 calls and $0.0135, or 0.45% to 1.35% of one Deep Research task.
So the cost of the report depends on Deep Research, not on the data calls. The thing worth your attention is whether the data can be checked.
| Capability | Catalog price per call | Calls in one report | Subtotal |
|---|---|---|---|
google_news/search | $0.000792 | 3 (English, Spanish, Chinese) | $0.002376 |
reddit/search | $0.000556 | 3 | $0.001668 |
reddit/comments | $0.000556 | 10 | $0.005560 |
youtube/search | $0.000556 | 2 | $0.001112 |
youtube/comments | $0.000556 | 5 | $0.002780 |
| Total | — | 23 | $0.013496 |
How long it takes: minutes for Deep Research, 77 seconds for our 7 calls
Deep Research runs for minutes. The comparison table in the docs lists normal model latency in seconds and Deep Research latency in minutes, async and in the background. The limit is 60 minutes, and most tasks finish in 20.
On 2026-03-05, a forum user who builds compliance research said that one run of the old agent took about 7 minutes. Later runs with similar prompts stayed in in_progress. The stream showed four or five thought steps, and then the connection dropped without an error (developer forum thread). Your polling code needs its own timeout for in_progress, not only handlers for completed and failed.
Our 7 calls took about 77 seconds in sequence. Comments were the slowest: 30.1 seconds for 50 YouTube comments and 19.3 seconds for 35 Reddit comments. News searches took 3.7 to 4.7 seconds each. In route A, the agent waits for each call. A dozen comment calls add a few minutes to a run that already takes many minutes.
Slow requests such as comments should not keep the agent waiting. The everyinfra_call_api tool description tells the agent what to do. For slow tasks or a large limit, it says to pass mode=async. The agent then gets a job_id at once and reads the result with everyinfra_get_job, which is free.
Each of our 7 synchronous responses also carried an async_hint that points to async mode, so the agent can read it. In route B, your program can run the calls in parallel. A few dozen calls finish in one or two minutes, and then you hand everything to Deep Research at once.
Citation format: url_citation, file_citation and byte offsets
Deep Research does not put footnotes in the report text. It attaches citations to the annotations array of the output step. The Interactions API reference lists several annotation types (API reference, updated 2026-10-28). Two of them matter here. url_citation has four fields: url, title, start_index and end_index. file_citation has document_uri, file_name, source, custom_metadata, page_number and media_id, plus the same two index fields.
The reference says that the indexes count bytes and that end_index is exclusive. This matters for any report that has non-ASCII text. In UTF-8, a curly quote takes 3 bytes and an accented Spanish letter takes 2. If you slice the Python string with these indexes, every citation after the first special character shifts. Encode the text to bytes first, then slice. The code below uses the field names from the reference, and it is a configuration example.
# Configuration example: map Deep Research citations back to text spans (field names from the Interactions API reference)
def cited_spans(interaction):
out = []
for step in interaction["steps"]:
if step.get("type") != "model_output":
continue
for block in step.get("content", []):
if block.get("type") != "text":
continue
raw = block["text"].encode("utf-8") # indexes count bytes
for a in block.get("annotations", []):
span = raw[a["start_index"]:a["end_index"]].decode("utf-8", "replace")
meta = {m["key"]: m.get("string_value", m.get("numeric_value"))
for m in a.get("custom_metadata", [])}
out.append({"type": a["type"], "text": span,
"url": a.get("url") or meta.get("source_url"),
"row_id": meta.get("row_id")})
return outMCP calls and results appear as two more step types. mcp_server_tool_call has name, server_name, arguments and id. mcp_server_tool_result has call_id and result, and call_id links it back to the call. The reference does not say whether MCP results produce url_citation entries. So in route A, do not assume that a sentence about a Reddit thread carries the thread URL as a citation.
A safer method is to tell the agent to write the row id and url in the sentence. After the run, check each one against the stored mcp_server_tool_result steps. In route B with File Search, the custom_metadata that you add to each document comes back in file_citation (File Search docs, "Citations", updated 2026-10-13). That is the only documented way to bring your own row ids back inside a citation.
| Where the cited text came from | Annotation type | What comes back | How to check |
|---|---|---|---|
| Pages read by Google Search or URL Context | url_citation | URL, title, byte range | Open the URL and compare the sentence |
| Your documents in File Search | file_citation | File name, custom_metadata, byte range | Use the row id in metadata to find the raw row |
| Rows returned by a remote MCP server | Not documented | Full mcp_server_tool_result in the steps | Ask for id and url in the text, then compare |
Route A: give the Gemini Deep Research API the EveryInfra MCP server
Route A is the mcp_server block in the curl example above. Three fields need a closer look. url is https://api.everyinfra.com/mcp, a public HTTPS endpoint that follows the MCP specification dated 2026-07-28. That version removed the initialize handshake. Each request carries its own protocol version, and in Streamable HTTP each message is one POST (MCP changelog, transports).
headers carries Authorization: Bearer <your EveryInfra key>. Our endpoint accepts this form, and the example in Google's docs has the same shape. The MCP specification makes auth optional, and OAuth 2.1 tokens go in the same header (MCP authorization). The full specification is at the MCP 2026-07-28 index, with sections for servers, clients and transports.
allowed_tools deserves the most care. On 2026-11-02 at 00:15 SGT, we called tools/list without a key. It returned 12 tools in 16,247 bytes.
Only 3 of them matter for research. everyinfra_list_capabilities lists platforms and capabilities, everyinfra_call_api calls any data capability, and everyinfra_get_job fetches async results. The other 9 are one web search tool and tools for account management. A research task does not need them.
An unattended research agent gains nothing from those 9 tools. First, tool definitions use context. All 12 definitions take about 16,610 bytes, and the 3 research tools take 3,309 bytes, about 80% less. Second, everyinfra_call_api has destructiveHint set to true because it costs money. Account actions should not come from a background task with nobody watching.
The MCP tools section adds a warning. Clients must treat tool annotations as untrusted unless they come from trusted servers (MCP tools specification). So do not expect Deep Research to slow down because it sees destructiveHint. The control that you can rely on is the allow list that you write in allowed_tools.
| Tool | Definition size (bytes) | Use for research? | Reason |
|---|---|---|---|
everyinfra_list_capabilities | 816 | Yes | Free; look up names and parameters first |
everyinfra_call_api | 1,695 | Yes | Fetches data; billed per call, no charge on failure |
everyinfra_get_job | 798 | Yes | Free; fetches async results |
everyinfra_search | 2,632 | No | Google Search already covers web search |
The prompt must work with the tools. The best practices section of the Deep Research page suggests that you tell the agent what to do when data is missing. One example is to say that a number is unknown, not to estimate it.
For social data, the prompt should say at least three things. First, each claim about a social platform carries the row id and url. Second, the agent writes "about" for dates that are not exact. Third, the agent calls everyinfra_list_capabilities before each new capability and does not guess parameters.
The third rule has a reason. EveryInfra returns a 422 for unknown parameters and invalid values. The error lists the allowed values and a suggestion, and no charge is made. An agent that reads the error can fix its own call, and the next section has a real example. For more on error handling, see API errors and self-healing. For MCP setup in other clients, see remote MCP setup and the MCP server page.
One real round trip: what the agent sends and what comes back
We did not run Deep Research. But the MCP specification fixes the format of the request that a client sends to a server. It is a JSON-RPC tools/call with a tool name and arguments. We sent the same JSON-RPC format to our MCP endpoint with a test key.
This shows only the server side: what the server gets and what it returns. We did not test the Deep Research side. We do not know which tool it picks or how it fills the arguments. We also do not know how it reads the rows, or whether it turns them into citations. To see that, run one task yourself and read mcp_server_tool_call and mcp_server_tool_result.
On 2026-11-02 at 00:16:51 SGT, we called everyinfra_call_api with platform=reddit and action=search. The query was e-bike battery fire, with sort=relevance and limit=10. The response came back in 6.0 seconds with status 200 and a count of 6.

These 6 rows show three things. First, the limit was 10 but only 6 threads came back. This capability returns only threads that match the query. The catalog lists three kinds of match. The words are in the title or community name, or in the whole thread, or next to each other in the text. The time range is fixed to the last month.
Second, the 6 threads came from 5 communities: r/nyc, r/BronxNY, r/ebikes, r/interesting and r/MTB. Together they had 1,293 comments. One r/interesting thread about how hard lithium fires are to put out had 1,137 comments alone. An agent that reads only titles can drift toward such a popular thread and away from the Bronx fire.
Third, every row has a url and a posted_at exact to the second. All the checks later in this article depend on these two fields. Field details are on the Reddit search capability page.
In the same minute, we made two free calls. At 00:20:00 SGT, everyinfra_list_capabilities for Reddit came back in 0.28 seconds.
At 00:20:07 SGT, we set sort to latest on purpose. The response came back in 0.19 seconds with isError: true and the message "sort must be one of: controversial, newest, popular, relevance, rising, top (got 'latest')". did_you_mean was newest, and the message ended with "Nothing was charged". For an unattended agent, this message means it can fix the call and retry. It will not record a failed call as "no discussion on Reddit".
Route B: pull structured social data first, then hand it to the Gemini Deep Research API
Route B takes data collection out of the agent's hands and puts it in your program. Between 00:16 and 00:19 SGT, we made 7 paid calls for one report. They covered news in three languages, Reddit threads and comments, and YouTube videos and comments. The table below lists each call, and charged_usd is the value from the billing field.
| Time | Capability | Main parameters | Rows | Charged | Time taken |
|---|---|---|---|---|---|
| 00:16:32 SGT | google_news/search | e-bike battery fire, us / en, last month | 10 | $0.000792 | 4.3 s |
| 00:16:51 SGT | reddit/search (through MCP) | e-bike battery fire, relevance | 6 | $0.000556 | 6.0 s |
| 00:17:23 SGT | reddit/comments | One r/nyc thread, limit 50 | 35 | $0.000556 | 19.3 s |
| 00:18:02 SGT | youtube/search | e-bike battery fire, relevance | 10 | $0.000556 | 8.6 s |
| 00:18:29 SGT | youtube/comments | One FDNY video, popular, limit 50 | 50 | $0.000556 | 30.1 s |
| 00:19:16 SGT | google_news/search | incendio batería bicicleta eléctrica, mx / es | 10 | $0.000792 | 4.7 s |
| 00:19:36 SGT | google_news/search | Chinese query on e-bike battery fires, hk / zh | 10 | $0.000792 | 3.7 s |
| Total | 5 capabilities | — | 131 | $0.004600 | 76.9 s |
The parameters, allowed values and fields for these 5 capabilities are in the catalog by platform, and no key is needed. See the Reddit catalog, the YouTube catalog and the Google News catalog. The prices, limit caps and field notes in this article come from these catalogs on 2026-11-02. Use the price_usd value in the catalog on the day you call.
After the calls, turn rows with different fields into one table where every row can be checked. Keep at least six columns. row_id joins the platform and the source id, for example reddit:t3_1xjb3ss. source_url opens that exact item. Then add platform, published_at, date_precision and fetched_at. date_precision says second, day, week or unknown, and fetched_at is the time of your call. The four tests below show why the precision column is necessary.
You can hand the table over in two ways. The first way is to put it in input.
Deep Research takes multimodal input, and the Google blog lists PDF, CSV, images, audio and video. The docs pass files as {"type": "document", "uri": ..., "mime_type": "application/pdf"}. A 131-row table is about 20,000 tokens, which is small for a one-million-token window. The second way is a File Search store. Upload each row or source as a document, with row_id, source_url and date_precision in custom_metadata. Citations then come back as file_citation entries that carry those fields.
# Configuration example: turn EveryInfra responses into checkable rows for Deep Research (Gemini side not run)
import csv
def rows_from(resp, platform, fetched_at):
for r in resp["results"]:
url = r.get("url")
if platform == "youtube_comments": # comment rows have no url, so build one from the video url and comment id
url = f'{resp["_video_url"]}&lc={r["id"]}'
exact = isinstance(r.get("posted_at"), str) and r["posted_at"][:4].isdigit()
yield {"row_id": f'{platform}:{r.get("id") or r.get("rank")}',
"source_url": url, "platform": platform,
"published_at": r.get("posted_at") or r.get("published_at") or "",
"date_precision": "second" if exact and platform != "news" else ("day" if exact else "unknown"),
"fetched_at": fetched_at,
"text": (r.get("title") or r.get("text") or "")[:500]}
with open("evidence.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=["row_id", "source_url", "platform", "published_at",
"date_precision", "fetched_at", "text"])
w.writeheader()
# for each saved response: w.writerows(rows_from(resp, "...", "2026-11-02T00:16:51+08:00"))Google's pages disagree on one point, so test it first. The limitations of File Search say that built-in retrieval tools cannot be combined. For example, File Search cannot be used with Google Search or URL Context in the same request. But the Google blog says that Deep Research can use Google Search, remote MCP, URL Context, code execution and File Search at the same time. The File Search example on the Deep Research page compares internal reports with recent web news, but its code turns on only File Search.
Until Google makes this clear, run one small task with both file_search and google_search. If it fails, put your table in input, not in File Search.
Test 1: news dates come from "days ago" labels
The English and Chinese results of google_news/search carry published_at as a full ISO timestamp. That looks exact. But all 10 English results had the clock time 16:16:35 UTC, and all 10 Chinese results had 16:19:38 UTC. We sent those requests at 16:16:32 and 16:19:36 UTC, which is 00:16 and 00:19 SGT. So the field is the request time minus a "days ago" value. The date part has meaning, and the clock time does not.
We checked the date part against dates in the URL path. Of the 4 English results with a dated URL, 3 were 1 day late and 1 matched. The New York Times story had 2026/10/28 in the URL, and published_at said 2026-10-29. The NY1 story said 10/30 in the URL and 2026-10-31 in the field. Billy Penn had 10/17 in the URL and 2026-10-18 in the field. The City Reporter matched.
| English outlet | Date in URL | `published_at` date | Days late |
|---|---|---|---|
| The New York Times | 2026-10-28 | 2026-10-29 | 1 |
| Spectrum News NY1 | 2026-10-30 | 2026-10-31 | 1 |
| Billy Penn at WHYY | 2026-10-17 | 2026-10-18 | 1 |
| The City Reporter | 2026-10-30 | 2026-10-30 | 0 |
Chinese results were off by more, up to 4 days, which suggests coarser labels such as "1 week ago". Spanish results were worse in a different way. All 10 had published_at set to null, and only one Spanish URL had a date in it.
The effect on a report is concrete. Suppose the report says that English outlets covered the Bronx fire within one day. English dates can be 1 day late, so that claim needs the URL date or the article itself.
Spanish dates are empty, so a Spanish timeline cannot come from this field at all. In the table, set date_precision to "day, may be 1 day late" for English and "unknown" for Spanish. Prefer the URL date when the URL has one. Field notes are on the Google News search capability page.
Test 2: one fire, four sources, three death counts
Rows that can be checked do not always agree with each other. The Bronx fire shows why. On 2026-10-28, The New York Times reported that an e-bike battery fire in a Patterson Houses apartment killed an 11-year-old boy. Fire Commissioner Lillian Bonsignore said it was the 401st e-bike battery fire of the year (The New York Times, 2026-10-28). Gothamist reported the FDNY finding on the same day (Gothamist, 2026-10-28).
On 2026-10-31, the New York Daily News reported that 3 more people from the same fire had died. It put the year's lithium battery fire deaths at 9 (New York Daily News, 2026-10-31). Spectrum Noticias, a Spanish outlet, quoted the commissioner's earlier numbers. These were 401 fires, 74 injuries and 6 deaths this year, against 292 fires, 51 injuries and 1 death last year (Spectrum Noticias, 2026-10-31). On 2026-10-14, Streetsblog NYC had reported 5 deaths so far and a 41% rise in fires (Streetsblog NYC, 2026-10-14).
| Source | Published | Fires this year | Deaths this year | Number came from |
|---|---|---|---|---|
| Streetsblog NYC | 2026-10-14 | Up 41% | 5 | FDNY data |
| The New York Times | 2026-10-28 | 401st fire | No yearly total | Fire commissioner |
| Spectrum Noticias | 2026-10-31 | 401 | 6 | Commissioner, 2026-10-28 briefing |
| New York Daily News | 2026-10-31 | 401 (as of last week) | 9 | FDNY officials |
These numbers do not conflict. They are snapshots of one number at different times. Five was the mid-October count, six was the count on the day of the fire, and nine came after three more deaths. But suppose a report says that "Spanish media reported 6 deaths this year" and links to the 2026-10-31 story. A reader opens the link and the quote matches, but the fact is already out of date.
So the table needs one more column for numbers: when the number was said, not only when the story was published. Research supports this. A May 2026 paper evaluated 14 models on deep research reports. Citation links were valid more than 94% of the time and relevant more than 80% of the time. But factual accuracy was only 39% to 77% (arXiv 2605.06635).
The same paper found that fact-check accuracy fell by about 42% on average as tool calls rose from 2 to 150. A link that works does not prove that the sentence is right. The numbers in the table above come from news reports and show how citations go out of date. For exact fire and casualty numbers, use the official FDNY releases. The City Reporter's story on fires in public housing, dated 2026-10-30, is one more source that a report could cite (The City Reporter, 2026-10-30).
Test 3: can a comment lead back to its source? Reddit 35 of 35, YouTube 0 of 50
Beyond news, most social research is about comments. We pulled two sets. One was the comments on the r/nyc thread about e-bike fires in public housing. The other was the popular comments on an FDNY YouTube video about an e-bike shop fire. The two sets were very different on traceability.
Each of the 35 Reddit comments had a url in the form reddit.com/r/nyc/comments/1xjb3ss/comment/19rvuy7xzfh7n/. Opening it shows that one comment. Each posted_at was exact to the millisecond, for example 2026-10-30T14:43:08.086000+00:00. A report that says "commenters on r/nyc said ..." can link that exact comment, and a reader can check it with one click.
The thread itself showed 38 comments, and we got 35. The missing ones may have been deleted or collapsed. We tested why Reddit comment counts differ in Reddit comment completeness. The r/nyc thread itself is public (r/nyc thread).
The 50 YouTube comments had no url field. posted_at held relative times such as "1 year ago" or "7 months ago". Of the 50, 15 said "year", 4 said "(edited)", and 14 were replies.
This has two effects. First, you cannot link a comment directly. In our table we built a link from the video URL plus &lc=<comment id>. This is a common way to open a comment on the YouTube website. But it is not a returned field, and we did not find Google documentation for that parameter, so we mark it as "built".
| Field check | Reddit comments (35 rows) | YouTube comments (50 rows) |
|---|---|---|
Direct url per comment | 35 | 0 |
Absolute posted_at | 35, to the millisecond | 0, relative text only |
| Times that say "year" | 0 | 15 |
| Marked "(edited)" | Not shown | 4 |
| Replies in the set | Shown in thread | 14 |
Second, "1 year ago" is exact only to the year or month, and only relative to the request time. A report on "YouTube discussion in the past month" can confirm only 4 of these 50 comments: "1 hour ago", "2 weeks ago" and two "3 weeks ago". The catalog notes for youtube/comments say that the since parameter filters by comment date, so you can limit the range when you fetch. Reply paging is covered in YouTube comment replies and pagination. Field details are on the YouTube comments capability page.
Test 4: YouTube relevance search returns mostly old videos
The time problem is clearer in YouTube search results. We used the same query, e-bike battery fire, in the same minute. All 10 news results were from the last 30 days. The top 10 youtube/search results by relevance were 2 from 2022, 4 from 2023, 2 from 2024, 1 from 2025 and 1 from 2026. The median year was 2023. The one 2026 video was published on 2026-09-09, which is also outside the last 30 days.
The data is not wrong. YouTube relevance ranking favors videos with many views and a long history. The most viewed of the 10 had 510,000 views and was from 2022. But suppose an agent treats comments on these 10 videos as current public opinion. Its report will then mix in talk from three or four years ago.
The fix is simple. For recent discussion, use sort=newest, or filter rows by posted_at in your table. For long-term discussion, state the time range in the report. We discuss this kind of sample bias in social media research sample integrity. Search fields are on the YouTube search capability page.
Context budget: 131 rows, about 20,000 tokens, 8% of a typical task
Route B puts data in the input, so you need to know its size. The raw JSON from our 7 calls was 79,787 bytes. At about 4 bytes per token, that is 19,947 tokens. The model page lists an input window of 1,048,576 tokens and an output limit of 65,536 tokens. The docs estimate about 250,000 input tokens for a standard task and about 900,000 for a Max task. Our data is 8% of a typical task input, so it leaves the agent plenty of room for its own searches and reading.
A cleaned table is smaller still. The raw responses have many fields that research does not need, such as thumbnail URLs, channel statistics and billing details. With our six columns and up to 500 characters of text, 131 rows shrink to less than half of the raw size.
There is a warning in the other direction. The best practices say that multimodal input adds cost and can overflow the context. The real risk is not 131 rows. It is a thousand comments from dozens of threads. With that many, filter by topic and time first, or use File Search for retrieval, before you put rows in input.
How structured social data makes citations checkable
The four tests lead to one simple method. The goal is that a reader can trace each claim about social media to one row. The row must show where the item is on the platform and how exact its time is.
First, each row needs a link that opens the item. Reddit threads and comments, YouTube videos and news meet this rule. YouTube comments do not, so build the link from the video URL and comment id and mark it as built. Second, each row needs a time precision. We saw four levels in this test: milliseconds for Reddit comments, seconds for Reddit threads and YouTube videos, and days for English news. The last level, relative or missing times, applied to YouTube comments and Spanish news.
Third, record fetched_at, the time of your call. Relative times and numbers like "the 401st fire this year" only make sense with that time.
Fourth, a claim with a number needs "who said it and when". The death count example shows that a working link does not keep a number current. Fifth, carry the row id into the citation. With File Search, put it in custom_metadata. With MCP or input, tell the agent to write row_id after each sentence.
| What we found | Risk to the report | What to do in the table |
|---|---|---|
News published_at uses the request clock time; dates 0 to 1 day late in English | Wrong timeline | date_precision=day; prefer the URL date |
| All 10 Spanish news dates empty | No timeline possible | date_precision=unknown; open the story for its date |
| YouTube comments: 0 of 50 with links, relative times | Citation cannot reach the source | Build the link and mark it; limit time with since or sort |
| YouTube relevance search: 9 of 10 from before 2026 | Old talk read as current | Filter by posted_at, or use sort=newest |
| Death counts of 5, 6 and 9 from different dates | Valid link, stale fact | Add a "when the number was said" column |
| Reddit search: 6 threads from 5 communities, one with 1,137 comments | Agent drifts to a popular side topic | Keep community and filter by topic |
None of these steps needs a new Gemini feature. The current citation types are enough: url_citation for web pages and file_citation with metadata for File Search. What is missing is checkable input data. This is why we suggest route B when you can use it.
In route A, the agent gets raw responses. Whether it notices that YouTube comment times are relative depends on its judgment in that run. In route B, your program makes these decisions once and writes them as the same columns in every row. The agent only has to cite them.
Check the catalog: 10 of 38 comment capabilities return a link
Test 3 covered only Reddit and YouTube. To see if comments on other platforms lead back to the source, you do not need a live call on each one. The free catalog lists response_fields for each capability. We read GET /api/v1/social/catalog on 2026-11-02 at 00:28 SGT. It listed 573 capabilities, and 569 of them were available. Of the available ones, 38 are comment capabilities, with comment or replies in the action name.
All 38 list a time field (posted_at or created_at). But only 10 return a url for each comment. The other 28 have no link. Of those 28, 27 return at least a comment id. For these, you can build a link from the post address and the id, as we did for YouTube. One capability returns neither a link nor a comment id.
| Comment capabilities | `url` on each row | Capabilities (catalog names) |
|---|---|---|
| With a link | 10 | reddit/comments, reddit/user_comments, twitter/comments, threads/comments, instagram/comments, linkedin/comments, github/issue_comments, netease_music/comments, gab/replies, truth_social/replies |
| No link, comment id present | 27 | Includes youtube/comments, tiktok/comments, facebook/comments, weibo/comments, douyin/comments and xiaohongshu/comments |
| No link and no comment id | 1 | naver/comments |
So the link column in your table needs two values: "source link" and "post link plus comment id". Tell the agent to write "see the comments under this post" in the second case. Do not let the report suggest that a reader can click straight to the comment.
A field in the catalog does not prove that the value is exact. The catalog also lists posted_at for youtube/comments, but our live call returned relative times such as "1 year ago". The catalog tells you whether a field exists. A live call tells you how exact it is. The catalog is free, and in MCP it is everyinfra_list_capabilities, so your prompt can tell the agent to check it before it pulls comments.
A second example for New York readers: battery safety beyond one fire
The same method works for related topics. NYC has run a lithium battery safety program since 2023. The Mayor's Office page from 2024-07 gives a figure for 2023. In that year, 59% of lithium battery fires started on batteries that were not charging (NYC Mayor's Office, 2024-07).
Other cities face the same issue. A CBC explainer from October 2026 collects firefighter advice (CBC, 2026-10). Billy Penn covered fire safety in Philadelphia on 2026-10-17 (Billy Penn at WHYY, 2026-10-17).
A report on how public advice changed over time would mix three kinds of rows. City pages give official statements with fixed dates. News gives dated stories, but the dates in our test were up to 1 day late. Social posts give opinions, with exact times on Reddit and relative times on YouTube. Each kind needs its own date_precision, and the prompt should tell the agent not to mix them in one timeline without a note.
What does not work, and what to watch
First, you cannot ask for structured output. The limitation is clear, so "return a JSON table" will not work. For machine-readable results, ask for a fixed Markdown table and parse it. Or follow the docs and use previous_interaction_id with a normal model. The docs use gemini-4-argon in the example, and normal models do support structured output.
Second, agent versions retire. Both current agent names carry preview and 04-2026. The December 2025 agent, deep-research-pro-preview-12-2025, was deprecated on 2026-10-08 and shut down on 2026-10-23. That was about ten and a half months from launch (changelog, deprecations). Keep the agent name in config, not in code.
Third, Google Search results have usage rules. The Gemini API additional terms say that Grounding with Google Search results must be shown to the end user with the search suggestions. They also must not be cached, resold, analyzed or used for training. A few cases allow storage for up to two years (Gemini API additional terms). If you archive or reuse reports, read that section first. It covers Google Search results, and data from your own MCP server or files falls under its own terms. This article is not legal advice.
Fourth, think about security. The safety section of the Deep Research page names three risks. They are prompt injection in files, risky web content, and data leaks when the agent reads internal data and the web together. Social comments are public user text, and they can contain instructions aimed at AI. Our MCP server returns user text as it is, so tell the agent that comment text is data, not instructions.
Your EveryInfra key in headers goes to our server with every MCP request. Create a separate key with a spending limit for Deep Research. Then you can turn off that key alone.
Fifth, read usage for cost. The agent decides how much to read and search, so you can only estimate in advance. Google suggests that you limit scope in the prompt.
On the Google developer forum, the product manager for the feature replied to a user. Final usage appears in the usage field of the Interaction object, and countTokens does not work for agents (developer forum thread, 2025-12-21). On our side, each response shows the cost in billing.charged_usd. Empty results and failures are free, as the pricing page explains.
Sixth, URL Context has limits. The docs say that it handles up to 20 URLs per request and up to 34 MB per URL. It does not support paywalled content or YouTube videos (URL context docs). So Deep Research cannot get comments by reading a YouTube video page. That is the reason to fetch them first with youtube/comments.
| Limit | What the docs say | What to do instead |
|---|---|---|
| Structured output | Not supported | Parse a fixed Markdown table, or pass the result to a normal model |
| Agent version | Preview names; the December 2025 agent shut down on 2026-10-23 | Keep the agent name in config |
| Google Search results | Show with search suggestions; no caching or analysis | Read the terms before you archive reports |
| Prompt injection | Named as a risk for files and web pages | Tell the agent that comment text is data |
| Cost | Known only after the run, in usage | Limit scope; use a separate EveryInfra key with a cap |
| URL Context | 20 URLs, 34 MB each, no YouTube videos | Fetch comments first with youtube/comments |
Recent changes
On 2026-10-27, Google released gemini-api, a beta command line tool. It calls the Interactions API and hosted agents from scripts and CI (Gemini API CLI docs). For you, a scheduled Deep Research report does not need a Python program. One command and a scheduler are enough.
On 2026-10-23, the old Deep Research agent shut down, and on 2026-10-13, Gemini 4 Argon became generally available. For you, code that still uses the December agent name no longer works. Change it to deep-research-preview-04-2026.
FAQ
How do I call the Gemini Deep Research API from Python?
Use the google-genai package. The Interactions API needs version 2.3.0 or later (Interactions API overview), and the source is in the python-genai repository. Call client.interactions.create(agent="deep-research-preview-04-2026", input=..., background=True). Then loop on client.interactions.get(id) until the status is completed or failed. To add MCP, put {"type": "mcp_server", "url": ..., "headers": ...} in tools. This question comes from the Google autocomplete phrase "gemini deep research api python".
How does Gemini Deep Research API pricing work, and is there a free tier?
There is no separate price. You pay for model inference plus tools, and Google estimates $1 to $3 per standard task and $3 to $7 per Max task. The Google blog says that the public preview is on paid tiers, so billing must be on. Google Search includes 5,000 free searches a month, then $14 per 1,000. This question comes from the autocomplete phrases "gemini deep research api pricing" and "deep research api free".
Can I use the Gemini Deep Research API on Vertex?
Yes. Google Cloud has its own Deep Research page. It uses the global v1beta1 endpoint on aiplatform.googleapis.com, Google Cloud access tokens, and the half-price service_tier="deferred" option. The pricing page gives a default Google Search quota of 1,000,000 a day on Vertex. The Gemini Developer API default is 1,500 a day (Vertex grounding docs). This question comes from the autocomplete phrase "gemini deep research api vertex".
What do I do when a Deep Research task stays in_progress?
A forum user reported this in March 2026 with the old agent. The interaction started, but it stayed in_progress with no usage. The docs suggest streaming with a saved last_event_id, so you can resume after a drop. Also add your own timeout. After 60 minutes, the documented maximum, cancel the task and log it. This question comes from the forum thread and the autocomplete phrase "gemini deep research stuck on starting research".
Can Deep Research read Reddit or YouTube comments by itself?
It can read public pages with Google Search and URL Context. But the URL Context docs say that YouTube videos are not supported, and comments that load later on a page may not appear. For stable comment data, give the agent structured rows through MCP or a prepared table, from reddit/comments and youtube/comments. This question comes from Reddit threads that ask whether a real deep research tool exists for MCP (r/LocalLLM thread).
Where do the Gemini Deep Research API key and the EveryInfra key go?
Put the Gemini key in the x-goog-api-key header, or let the SDK read GEMINI_API_KEY from the environment. Put the EveryInfra key in the headers of the mcp_server tool as Authorization: Bearer <key>. Do not put either key in the prompt text. This question comes from the autocomplete phrase "gemini deep research api key".
How to start
First, sign up for EveryInfra and get an API key. You can browse the catalog and try one call for free in the data market, and the quick start is in the docs. Second, skip Gemini at first. Call reddit/search or google_news/search with curl, and check that url, posted_at and billing look like the examples here. The platform pages are Reddit data API, YouTube data API and Google News API.
Third, use the route A example. Put https://api.everyinfra.com/mcp in Deep Research tools, and keep only 3 tools in allowed_tools. Run a small topic and check the mcp_server_tool_call steps. Fourth, use route B when you need a report that readers can check. Fetch the data, build the six columns, and hand the table to Deep Research. For parallel data fetching with subagents, see Claude Code subagents for TikTok accounts. For the new MCP specification in production, see MCP 2026 specification and production readiness.
References
- Gemini Deep Research agent, Google AI for Developers, updated 2026-10-13, https://ai.google.dev/gemini-api/docs/deep-research
- Deep Research preview model page, Google AI for Developers, updated 2026-10-29, https://ai.google.dev/gemini-api/docs/models/deep-research-preview-04-2026
- Interactions API overview, Google AI for Developers, updated 2026-10-15, https://ai.google.dev/gemini-api/docs/interactions-overview
- Interactions API reference, Google AI for Developers, updated 2026-10-28, https://ai.google.dev/api/interactions-api
- Background execution, Google AI for Developers, https://ai.google.dev/gemini-api/docs/background-execution
- Gemini Developer API pricing, Google AI for Developers, updated 2026-10-30, https://ai.google.dev/gemini-api/docs/pricing
- Rate limits, Google AI for Developers, updated 2026-10-28, https://ai.google.dev/gemini-api/docs/rate-limits
- File Search, Google AI for Developers, updated 2026-10-13, https://ai.google.dev/gemini-api/docs/file-search
- Grounding with Google Search, Google AI for Developers, updated 2026-10-28, https://ai.google.dev/gemini-api/docs/google-search
- URL context, Google AI for Developers, updated 2026-10-13, https://ai.google.dev/gemini-api/docs/url-context
- Gemini API changelog, Google AI for Developers, entry of 2026-10-30, https://ai.google.dev/gemini-api/docs/changelog
- Gemini deprecations, Google AI for Developers, updated 2026-10-22, https://ai.google.dev/gemini-api/docs/deprecations
- Gemini API CLI, Google AI for Developers, updated 2026-10-28, https://ai.google.dev/gemini-api/docs/cli
- Billing, Google AI for Developers, https://ai.google.dev/gemini-api/docs/billing
- Gemini API Additional Terms of Service, Google, https://ai.google.dev/gemini-api/terms
- Gemini Deep Research agent, AI Studio docs, Google, https://aistudio.google.com/docs/deep-research
- Use the Gemini Deep Research Agent, Google Cloud, https://docs.cloud.google.com/gemini-enterprise-agent-platform/agents/use-deep-research
- Grounding with Google Search, Google Cloud, https://docs.cloud.google.com/vertex-ai/generative-ai/docs/grounding/grounding-with-google-search
- Get started with Deep Research, Gemini cookbook notebook, https://github.com/google-gemini/cookbook/blob/main/quickstarts/Get_started_Deep_Research.ipynb
- python-genai, Google, https://github.com/googleapis/python-genai
- Introducing Deep Research and Deep Research Max, Google blog, 2026-04-21, https://blog.google/innovation-and-ai/models-and-research/gemini-models/next-generation-gemini-deep-research/
- Build with Gemini Deep Research, Google blog, 2025-12-11, https://blog.google/innovation-and-ai/technology/developers-tools/deep-research-agent-gemini-api/
- How to use Deep Research with the Gemini API, Philipp Schmid, 2026-04-29, https://www.philschmid.de/deep-research-update
- Deep Research API interaction stuck in_progress, Google developer forum, 2026-03-05, https://discuss.ai.google.dev/t/deep-research-api-interaction-stuck-in-progress-for-some-domains/129020
- Google Gemini Deep Research costs, Google developer forum, 2025-12-21, https://discuss.ai.google.dev/t/google-gemini-deep-research-costs/112804
- Deep Research agent API questions on rate limits and costs, Google developer forum, 2025-12-12, https://discuss.ai.google.dev/t/deep-research-agent-api-questions-for-rate-limitsand-costs/111904
- MCP specification 2026-07-28 index, Model Context Protocol, https://modelcontextprotocol.io/specification/2026-07-28
- MCP specification 2026-07-28 changelog, Model Context Protocol, https://modelcontextprotocol.io/specification/2026-07-28/changelog
- MCP transports, Model Context Protocol, https://modelcontextprotocol.io/specification/2026-07-28/basic/transports
- MCP authorization, Model Context Protocol, https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization
- MCP tools, Model Context Protocol, https://modelcontextprotocol.io/specification/2026-07-28/server/tools
- Cited but not verified: source attribution in deep research agents, arXiv, 2026-05-07, https://arxiv.org/html/2605.06635v1
- Benchmarking and error analysis of deep search and deep research agents, arXiv, 2026-10-21, https://arxiv.org/html/2610.29346v1
- DeepResearch Bench: a benchmark for deep research agents, arXiv, https://arxiv.org/abs/2506.11763
- EveryInfra data capability catalog, read 2026-11-02, https://api.everyinfra.com/api/v1/social/catalog
- EveryInfra catalog for Reddit, read 2026-11-02, https://api.everyinfra.com/api/v1/social/catalog?platform=reddit
- EveryInfra catalog for YouTube, read 2026-11-02, https://api.everyinfra.com/api/v1/social/catalog?platform=youtube
- EveryInfra catalog for Google News, read 2026-11-02, https://api.everyinfra.com/api/v1/social/catalog?platform=google_news
- Boy, 11, killed in e-bike battery fire in Bronx apartment, The New York Times, 2026-10-28, https://www.nytimes.com/2026/10/28/nyregion/fire-e-bike-battery-bronx.html
- Lithium-ion battery caused Bronx fire that killed boy, FDNY says, Gothamist, 2026-10-28, https://gothamist.com/news/lithium-ion-battery-caused-bronx-fire-that-killed-11-year-old-fdny-says
- E-bike fires have skyrocketed across NYC, New York Daily News, 2026-10-31, https://www.nydailynews.com/2026/10/31/as-bronx-family-reels-from-devastating-blaze-that-killed-4-e-bike-fires-have-skyrocketed-across-nyc/
- E-bike battery fires on the rise at NYCHA, The City Reporter, 2026-10-30, https://www.thecityreporter.nyc/2026/10/30/e-bike-battery-fires-on-the-rise-at-nycha-leaving-death-in-their-wake/
- Lithium-ion battery fires are up 41% as public fix stalls, Streetsblog NYC, 2026-10-14, https://nyc.streetsblog.org/2026/10/14/everyone-should-be-furious-lithium-ion-battery-fires-are-up-41-as-public-fix-stalls
- Four dead after e-bike battery fire in the Bronx, Spectrum Noticias, 2026-10-31, https://spectrumnoticias.com/ny/nyc/noticias/2026/10/31/cuatro-muertos-tras-un-incendio-en-la-bateria-de-una-bicicleta-electrica-en-el-bronx--nypd
- Boy, 11, dies in Bronx fire from an e-bike battery, Univision, 2026-10-29, https://www.univision.com/local/nueva-york-wxtv/muere-nino-de-11-anos-en-incendio-provocado-por-bateria-de-bicicleta-electrica-en-el-bronx
- Mayor Adams takes new actions to prevent lithium-ion battery fires, NYC Mayor's Office, 2024-07, https://www.nyc.gov/mayors-office/news/2024/07/mayor-adams-takes-new-actions-prevent-deadly-lithium-ion-battery-fires-promote-safe-e-bike
- What firefighters want you to know about lithium battery fires, CBC, 2026-10, https://www.cbc.ca/news/science/lithium-battery-fire-faq-9.7371004
- How to prevent lithium-ion battery fires in Philadelphia, Billy Penn at WHYY, 2026-10-17, https://billypenn.com/2026/10/17/lithium-ion-battery-fire-safety-philadelphia/
- E-bike battery fires on the rise at NYCHA, r/nyc thread, Reddit, 2026-10-30, https://www.reddit.com/r/nyc/comments/1xjb3ss/ebike_battery_fires_on_the_rise_at_nycha_leaving/
- Is there a true deep research tool for MCP, r/LocalLLM thread, Reddit, https://www.reddit.com/r/LocalLLM/comments/1pw1ukl/is_there_a_true_deep_research_mcp_deep_research/
Reference BL-66