Announcing CIMD support for MCP Client registration
Learn more

Google Sheets MCP vs API - Tool Calling Architectural Choices for Building AI Agents

Nityashree Yadunath
Product Marketing Manager

TL;DR

  • Google's Sheets MCP server is first-party, at sheetsmcp.googleapis.com/mcp/v1, and in Developer Preview. The program terms bar preview features from public applications before general availability. For a multi-tenant agent that is a licensing blocker, not a capability gap.
  • It exposes six tools. Five are narrow; update_spreadsheet is a passthrough to spreadsheets.batchUpdate carrying 69 documented request types, so the model authors raw request JSON rather than calling a named action.
  • Nothing creates a spreadsheet, copies a sheet across files, or resolves a spreadsheet by name. Name resolution sits on Google's separate Drive MCP server, so a working Sheets agent wires two preview servers together.
  • Both paths share one quota: 300 reads and 300 writes per minute per project, 60 of each per user. API batch methods compress many operations into one quota unit; get_values spends one per range. The documented MCP scope set also includes drive.readonly, which Google classifies as Restricted.
  • Scalekit's Google Sheets connector handles per-user OAuth, vaulted tokens, and refresh across 48 named tools, so this decision does not change your credential infrastructure.

Your agent needs to read and write Google Sheets. Until recently that meant the Sheets API v4 and nothing else. Google now ships a first-party remote MCP server for Sheets, alongside dedicated servers for Gmail, Drive, Docs, Slides, Calendar, and Chat. Both paths work. They are not interchangeable, and the difference that matters most for production agents is not in the tool list.

What Google Sheets MCP and the Sheets API actually are

Two objects, two different maturity levels. The MCP server is months old and gated. The API has been the spreadsheet integration surface for a decade.

The Sheets MCP server

Google's Sheets MCP server is a Google-hosted remote endpoint at sheetsmcp.googleapis.com/mcp/v1, transported over HTTP, authenticated with OAuth 2.0. You enable two services in a Google Cloud project: sheets.googleapis.com and sheetsmcp.googleapis.com. Then you register your own OAuth client and point an MCP host at the endpoint.

Tool calls run as the authenticated user and inherit that user's Drive and Sheets permissions. Official reference: the Sheets MCP server guide at developers.google.com/workspace/sheets/api/guides/configure-mcp-server.

The Sheets API v4 surface

The Sheets API v4 is a compact REST surface at sheets.googleapis.com: 17 methods across four resources. spreadsheets covers create, get, getByDataFilter, and batchUpdate. spreadsheets.values covers ten methods including append, batchGet, batchUpdate, and the data-filter variants. Two more resources handle developerMetadata and sheets.copyTo.

Auth accepts any Google OAuth credential: Authorization Code per user, or a service account with domain-wide delegation for headless work. Official reference: developers.google.com/workspace/sheets/api/reference/rest.

Why the Developer Preview label changes the decision

The MCP server ships under the Google Workspace Developer Preview Program. Enrollment is an application form tied to a specific Workspace account and Google Cloud project, with a turnaround measured in days. Service accounts cannot be enrolled.

The program terms are the part to read closely. Preview features may not be included in public applications before the general availability announcement, and members may not grant end users outside their own domain or company access to applications built on pre-GA APIs. For an internal agent, that is fine. For a B2B product, it is a hard stop.

Comparing them where it matters for agents

Four dimensions decide this: what the agent can call, what auth path you inherit, what you operate, and what the quota costs you.

What your agent can actually do

The naive read of "six tools versus seventeen methods" is wrong. update_spreadsheet is a wide envelope, so mutation coverage is close to parity. The gaps sit in reads, creation, and discovery.

Capability
Sheets MCP server (Developer Preview)
Sheets API v4
Read one range of values
Named tool: get_values
spreadsheets.values.get
Read many ranges in one lean call
Not available
spreadsheets.values.batchGet
Read metadata and grid data
Named tool: get_spreadsheet
spreadsheets.get
Write values or formulas to a range
Named tools: update_values, update_formulas
spreadsheets.values.update
Write or clear many ranges in one call
Via update_spreadsheet request JSON
values.batchUpdate, values.batchClear
Append rows after the last row of data
Via update_spreadsheet (appendCells)
spreadsheets.values.append
Insert rows or columns
Named tool: insert_dimension
insertDimension request
Charts, formatting, protected ranges, slicers, tables
Via update_spreadsheet request JSON
spreadsheets.batchUpdate
Create a new spreadsheet
Not available
spreadsheets.create
Copy a sheet into a different spreadsheet
Not available
spreadsheets.sheets.copyTo
Target ranges or search by developer metadata
Not available
getByDataFilter, developerMetadata.search
Subscribe to change events
Not available
Not in Sheets API; Drive subscriptions

Where the MCP ceiling actually is

update_spreadsheet maps to spreadsheets.batchUpdate and accepts 69 documented request types, from addChart and setDataValidation to addSlicer and refreshDataSource. Anything the batch endpoint can do, the MCP server can do.

The cost is that the model authors the request JSON. Instead of calling a tool named for the action, it constructs a repeatCell request with a nested cellFormat and a fields mask. That is a tool calling accuracy problem wearing a capability disguise. Wrong mask, silent no-op. Wrong index base, wrong cells.

The spreadsheet your agent cannot find

Every MCP tool takes a spreadsheet ID. None of them resolves a name. Google's own Sheets test prompt uses a literal ID; the cross-product prompt that starts from a spreadsheet title routes through drive.search_files on the Drive MCP server first.

So a working Sheets agent registers two Developer Preview servers, or three once Google's separate Universal Search MCP server enters the picture. Multi-server composition is the default case, not the edge case.

The auth path each one puts you on

The MCP server is OAuth 2.0 only, and you bring your own client ID and secret with a redirect URI that matches the host. Google documents a distinct callback path per client: one for Antigravity, another for Claude, where adding the custom connector also requires an Enterprise, Pro, Max, or Team plan.

The API takes the same Authorization Code grant and adds the option that matters for background work: a service account with domain-wide delegation, no browser, no user present. The preview program will not register a service account, which pushes headless Sheets agents toward the API by construction.

Scope classification is a shipping constraint

Google's setup guide has you add four scopes for the Sheets MCP server: drive.readonly, drive.file, spreadsheets.readonly, and spreadsheets.

Those are not equivalent in verification terms. Google classifies spreadsheets and spreadsheets.readonly as Sensitive, which means justification and a demo video. It classifies drive.readonly as Restricted, and storing or transmitting Restricted-scope data on your servers requires a third-party security assessment. drive.file is the only non-sensitive one in the set. If you can serve your use case with drive.file and spreadsheets, do that, and keep the Restricted scope out of your consent screen.

What you own in production, and what the quota costs

Both paths draw on the same budget: 300 read requests and 300 write requests per minute per project, and 60 of each per minute per user per project. Each MCP tool call bills as exactly one read or one write.

The asymmetry is in batching. A batch request, including every subrequest inside it, counts as one API request. Reading eight named ranges through values.batchGet is one unit; reading them through get_values is eight. For a reporting agent looping over 40 tabs, that is the difference between staying inside the per-user ceiling and hitting 429 mid-run.

Pricing and versioning are moving

Standard Sheets API use is free today. Google has stated that exceeding quota limits is planned to generate Google Cloud billing charges later in 2026, under its standardized tiering model for Workspace agent tools and APIs. Quota adjustments already landed for Gmail, Calendar, and Drive in May 2026.

Versioning cuts the other way. The API is pinned at v4 and has been stable for years. MCP tool schemas are a managed contract on a preview cadence you do not control. For a deterministic pipeline where an unannounced schema change is an incident, that distinction is the whole argument. The broader tradeoffs between these approaches are explored in the difference between MCP and APIs.

Change detection lives in Drive, not Sheets

Nothing in the Sheets API v4 surface subscribes to anything. There is no watch method and no event resource. The MCP server has no event surface either.

Change signals come from the Drive layer: Google Workspace Events API subscriptions on Drive resources are generally available and deliver file-edited events through Cloud Pub/Sub. Those events tell you a spreadsheet changed, not which cell. Cell-level diffing still means reading the sheet and comparing.

When to use MCP, when to use the API

The split is cleaner here than for most tools, because the preview gate does most of the deciding for you.

Use the Sheets MCP server when

  • You are building an internal agent for your own domain, where the preview restriction on external end users does not apply
  • An analyst is present in Antigravity or Claude and the work is exploratory: read this tab, reformat that range, insert a column
  • Your agent already knows spreadsheet IDs, or you are willing to run the Drive MCP server alongside it for name resolution
  • You want Google enforcing per-user Drive and Sheets permissions on every call without writing permission checks

Use the Sheets API when

  • You ship the agent to customers outside your company; the preview terms rule out the MCP path until general availability
  • The agent runs headless on a schedule and needs a service account with domain-wide delegation
  • The agent creates spreadsheets, copies sheets between files, or targets ranges by developer metadata
  • Read volume is high enough that values.batchGet and values.batchUpdate quota compression decides whether the run finishes
  • You need pinned schemas because an unannounced tool contract change would be a production incident

The credential problem neither path solves

Naming it plainly: both paths hand you a token per user and then stop.

What Google gives you

Google gives you the right security posture. Every call runs as the authenticated user, constrained by that user's Drive sharing and Sheets permissions. What the user can't do, the agent can't do. That is the model an enterprise security reviewer wants to see, and it is the same on both paths.

What Google does not give you

Google does not store, refresh, rotate, or revoke those tokens on your behalf. Forty customers means forty Google refresh tokens, encrypted at rest, isolated per tenant, and never written to a log. Access tokens expire on Google's one-hour cadence. Refresh tokens get revoked from a user's account settings with no notification to you, and your agent finds out through a 401 mid-run.

Refresh has to be proactive. Waiting for the 401 creates a race where several agent threads attempt refresh at once, each unaware of the others. That failure mode is identical whether the token came from an MCP consent flow or a direct API grant. The patterns behind handling token refresh for AI agents apply equally to both paths.

Where Scalekit sits

Scalekit's Google Sheets connector runs the per-user OAuth flow, vaults the tokens, refreshes them, and injects the right credential at execution time. Credentials never touch the agent runtime or the LLM context. The connector ships 48 tools over the Sheets API, so the surface is decomposed into named actions rather than one batch envelope.

Building a multi-tenant Google Sheets agent with Scalekit

The setup is one connection per environment and one connected account per user. Prerequisites: a Google Cloud project with the Sheets API enabled, and a connection created in the Scalekit dashboard under AgentKit and Connections.

One connection, per-user connected accounts

The connection_name string in code must match the connection name in the dashboard character for character. That mismatch is the single most common integration error.

import os from scalekit.client import ScalekitClient from dotenv import load_dotenv load_dotenv() scalekit_client = ScalekitClient( env_url=os.getenv("SCALEKIT_ENV_URL"), client_id=os.getenv("SCALEKIT_CLIENT_ID"), client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"), ) actions = scalekit_client.actions CONNECTION_NAME = "googlesheets" # must match the dashboard connection name IDENTIFIER = "user_123" # your app's user ID, email, or UUID response = actions.get_or_create_connected_account( connection_name=CONNECTION_NAME, identifier=IDENTIFIER, ) if response.connected_account.status != "ACTIVE": link = actions.get_authorization_link( connection_name=CONNECTION_NAME, identifier=IDENTIFIER, ) print("Authorize Google Sheets:", link.link)

Retrieving the authorized tool surface

Before the tool code, the distinction worth being precise about: this is not loading a connector catalog. list_scoped_tools returns the tools this specific user's connected account is authorized to call, and the Google Sheets connector has 48 of them. Handing all 48 to the model is roughly 9,600 tokens of schema before the agent does any work, and a decision space no model handles well.

An allowlist is how a reporting agent narrows that to five.

from google.protobuf.json_format import MessageToDict REPORTING_TOOLS = { "googlesheets_get_values", "googlesheets_batch_get_values", "googlesheets_append_values", "googlesheets_batch_update_values", "googlesheets_add_chart", } scoped_response, _ = actions.tools.list_scoped_tools( identifier=IDENTIFIER, filter={"connection_names": [CONNECTION_NAME]}, page_size=100, ) tool_defs = [ MessageToDict(t.tool).get("definition", {}) for t in scoped_response.tools ] agent_tools = [d for d in tool_defs if d.get("name") in REPORTING_TOOLS] print(f"{len(agent_tools)} of {len(tool_defs)} Google Sheets tools in context")

Running the agent loop with LangChain

Scalekit's LangChain adapter wraps the same scoped surface as StructuredTool objects, each bound to the caller's connected account at construction time. No Google token enters agent code or model context.

from langchain.agents import create_tool_calling_agent, AgentExecutor from langchain_anthropic import ChatAnthropic from langchain_core.prompts import ChatPromptTemplate llm = ChatAnthropic(model="claude-sonnet-4-5", temperature=0) sheets_tools = scalekit_client.actions.langchain.get_tools( identifier=IDENTIFIER, connection_names=[CONNECTION_NAME], ) sheets_tools = [t for t in sheets_tools if t.name in REPORTING_TOOLS] prompt = ChatPromptTemplate.from_messages([ ("system", "You maintain a revenue tracker in Google Sheets. " "Read before you write. Use A1 notation for ranges."), ("human", "{input}"), ("placeholder", "{agent_scratchpad}"), ]) agent = create_tool_calling_agent(llm, sheets_tools, prompt) executor = AgentExecutor(agent=agent, tools=sheets_tools, verbose=True) result = executor.invoke({ "input": ( "In spreadsheet 1AbC_dEfGhIjK, read Q3!A1:F50, " "append a total row, and add a column chart of revenue by region." ) }) print(result["output"])

Executing a single tool from TypeScript

For a deterministic pipeline where the model is not choosing anything, call the tool directly. Same connected account, same vaulted credential.

import { ScalekitClient } from '@scalekit-sdk/node' import 'dotenv/config' const scalekit = new ScalekitClient( process.env.SCALEKIT_ENV_URL!, process.env.SCALEKIT_CLIENT_ID!, process.env.SCALEKIT_CLIENT_SECRET!, ) const connector = 'googlesheets' // must match the dashboard connection name const identifier = 'user_123' const result = await scalekit.actions.executeTool({ connector, identifier, toolName: 'googlesheets_append_values', toolInput: { spreadsheet_id: '1AbC_dEfGhIjK', range: 'Q3!A1', values: [['2026-08-25', 'EMEA', 148200, 'closed-won']], value_input_option: 'USER_ENTERED', insert_data_option: 'INSERT_ROWS', }, }) console.log(result)

Reaching endpoints the tool library does not name

Some Sheets endpoints have no named tool in any library, and the data-filter methods are the usual case. The connector's proxy request path sends an authenticated call to the raw API using the same connected account, so you do not fall back to managing a token yourself.

result = actions.request( connection_name=CONNECTION_NAME, identifier=IDENTIFIER, path="/v4/spreadsheets/1AbC_dEfGhIjK/values:batchGet" "?ranges=Q3!A1:F50&ranges=Q2!A1:F50", method="GET", ) print(result)

Why the Scalekit path holds up for multi-tenant Sheets agents

Three things carry the weight here: composition across servers, per-user isolation without per-user infrastructure, and an accountability record after the fact.

Virtual MCP servers for multi-tool agents

Google's model is one MCP server per product, so a Sheets agent that also touches Drive and Slack is three endpoints, three OAuth clients, three consent flows, and every tool on all three exposed to the model. Scalekit's Virtual MCP servers invert that: you declare the connections and the exact tools once per agent role and get one static mcp_server_url.

Per-user isolation runs through session tokens. One server definition serves every user, and each run gets a short-lived token scoped to that user's connected accounts.

from datetime import timedelta from scalekit.actions.models.mcp_config import McpConfigConnectionToolMapping vmcp = scalekit_client.actions.mcp.create_config( name="revenue-tracker-agent", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name="googlesheets", tools=[ "googlesheets_get_values", "googlesheets_batch_get_values", "googlesheets_append_values", ], ), McpConfigConnectionToolMapping( connection_name="googledrive", tools=["googledrive_search_files"], ), ], ) config_id = vmcp.config.id mcp_server_url = vmcp.config.mcp_server_url

Before each run, confirm the user's connections are still active, then mint the token.

accounts = scalekit_client.actions.mcp.list_mcp_connected_accounts( config_id=config_id, identifier=IDENTIFIER, include_auth_link=True, ) for account in accounts.connected_accounts: if account.connected_account_status != "ACTIVE": print(f"{account.connection_name} needs auth: {account.authentication_link}") token_response = scalekit_client.actions.mcp.create_session_token( mcp_config_id=config_id, identifier=IDENTIFIER, expiry=timedelta(minutes=30), ) mcp_server = { "url": mcp_server_url, "headers": {"Authorization": f"Bearer {token_response.token}"}, }

Tool call logs as the accountability record

A misconfigured database query leaks data passively. A misconfigured spreadsheet agent overwrites a range. The question afterwards is who authorized the call and which user's credential it ran under, and Google's OAuth log events answer neither at tool granularity.

Scalekit's downstream tool call logs carry that attribution on every entry: the authorizing user, the agent that ran it, the tool, and the response, exportable to your SIEM with failures separated by source. More on the reasoning in agent tool observability and audit-grade access control for multi-tenant agents.

Surface reduction is the accuracy lever

Forty-eight Sheets tools in context is an accuracy problem and a cost problem at once. The model picks googlesheets_update_values when it needed googlesheets_append_values, and you pay for the schema on every turn.

Scoping to the five tools a revenue tracker actually calls cuts the schema overhead by roughly 80% and shrinks the decision space to what is relevant for this user and this task. The fix is not better prompting. It is surface reduction. Model upgrades help; they are not the lever. Related reading: how tool calling auth changes when you move from single-tenant to multi-tenant and what an MCP gateway is and when to use one.

Which one to build against

For most tool comparisons the answer depends on the use case. Here the preview gate settles it, and what is left over is a credential decision.

Internal agents can take the MCP path

If the agent stays inside your own Workspace domain and a human is present, the Sheets MCP server is the faster route, and Google's permission inheritance is worth having. Register the Drive server alongside it and accept that both are pre-GA and unversioned.

Customer-facing agents cannot, yet

If you ship to customers, the decision is already made. The preview terms exclude external end users until general availability. The API is also where creation, cross-file sheet copying, data-filter targeting, service-account execution, and quota-efficient batch reads live.

The credential layer is the same either way

Forty tenants means forty Google grants to vault, refresh, and revoke, plus a tool call record that survives an audit. Neither path gives you that. It is infrastructure, and it deserves a deliberate decision rather than accretion.

Start with the Google Sheets connector docs, the Google Sheets agent connector overview, and the full connector catalog. Building across Workspace? The same pattern applies in Google Drive MCP vs API and Google Calendar MCP vs API. Volume estimates live on the pricing page.

Talk to other Google Sheets agent builders

Spreadsheet agents fail in specific ways: an off-by-one row index, a fields mask that silently no-ops, a refresh token revoked three weeks ago that nobody noticed.

Bring yours to the Scalekit Slack community and compare notes with people running the same connectors in production. If you are working against a deadline and want an engineer on it directly, use Talk to us. Want a running starting point instead? The revenue forecast commentary agent and CRM AI agent templates both read and write structured data on a user's behalf.

No items found.
Agent
Auth Quickstart
On this page
Share this article
Agent
Auth Quickstart

Acquire enterprise customers with
zero upfront cost.

Every feature unlocked. No hidden fees.