Skip to main content
Glama

sheetcraft-mcp

Google Sheets MCP server + CLI for AI agents — 34 tools across 6 opt-in toolsets. One shared engine, two surfaces:

  • MCP server — for chat agents (Claude Desktop, Claude Code, OpenCode, any MCP client). Tools appear in the agent's tool list and are permission-gateable.

  • CLI (sheets) — for scripts, pipes, and bulk work. Same 34 operations, same auth, same errors, one process per command.

Designed for agent reliability: teaching errors (a bad range returns an example + the list of available sheets, not a stack trace), token-efficient reads (CSV defaults, hard cell caps, explicit truncation notices), and write echoes (updatedRange/updatedCells on every write so the agent closes its own loop without a verification read).


Requirements

  • Node ≥ 20

  • A Google account, and either an OAuth Client ID (recommended — see Option A) or a service account key (see Option B)

  • Works on Linux, macOS, and Windows (all paths resolve under your home directory)

Related MCP server: Google Sheets MCP Server

Install

# Run directly with npx — no install step
npx sheetcraft-mcp@latest --help

# or install globally — then use the `sheets` and `sheets-mcp` commands
npm install -g sheetcraft-mcp

Three commands are installed:

Command

What it is

sheets

The CLI

sheets-mcp

The MCP server (stdio)

sheetcraft-mcp

Both — with arguments it runs the CLI, with none it starts the MCP server. This is what MCP configs use (npx sheetcraft-mcp@latest).

Quick start

1. Add the MCP config (OpenCode example; Claude Desktop and others in MCP configuration):

// opencode.json
{
  "mcp": {
    "sheets": {
      "type": "local",
      "command": ["npx", "-y", "sheetcraft-mcp@latest"],
      "enabled": true
    }
  }
}

2. Authenticate once (in a terminal — see Authentication for details):

npx sheetcraft-mcp@latest auth login

A browser opens → you consent → done. Tokens persist and auto-refresh; the MCP config itself contains no secrets.

3. Use it. In agents with terminal access (OpenCode, Claude Code), the agent can do this whole setup itself: the first Sheets tool call without credentials returns a teaching message that says exactly what to run. Tools appear as sheets_get_values, sheets_update_values, etc.


Authentication

Two modes. Pick one.

Option A: OAuth

Option B: Service account

Acts as

You (your Google account)

A robot account

Can create/copy spreadsheets

✅ Yes

❌ No (Google gives SAs a 0-byte storage quota)

Setup

Browser consent, once

Env vars + manual sharing of each file

Recommended for

Personal use, agents that create files

CI, servers, headless setups

The two-file mental model

OAuth confuses everyone exactly once — when they see two JSON files. Here is the whole thing:

client_secret_xxx.json   your APP's identity with Google  → used ONCE by `auth login`
oauth-tokens.json        YOUR logged-in session           → created automatically, auto-refreshes

The client_secret_*.json you download from Google is not a credential for the MCP config or env — it's the key fob that lets the tool open a login flow. It's consumed once by auth login; after that the saved token does all the work and you can even delete the JSON.

1. In Google Cloud Console:

  • Enable Google Sheets API and Google Drive API

  • Create Credentials → OAuth client ID → Desktop app → download the JSON

2. Hand the file to auth login — any one of these three ways:

# (a) zero file moves — point at the download directly:
npx sheetcraft-mcp@latest auth login --client ~/Downloads/client_secret_xxx.json

# (b) or park it in the config dir once, then plain login forever after:
mkdir -p ~/.config/sheetcraft-mcp
cp ~/Downloads/client_secret_xxx.json ~/.config/sheetcraft-mcp/oauth-client.json
npx sheetcraft-mcp@latest auth login

# (c) or skip the file — set the values it contains as env vars:
#     GOOGLE_OAUTH_CLIENT_ID=…xxx.apps.googleusercontent.com
#     GOOGLE_OAUTH_CLIENT_SECRET=…
npx sheetcraft-mcp@latest auth login

3. Browser opens → consent → done. Verify:

npx sheetcraft-mcp@latest auth status

Tokens persist at ~/.config/sheetcraft-mcp/oauth-tokens.json (permissions 0600) and auto-refresh on every use.

Useful auth commands:

npx sheetcraft-mcp@latest auth status   # which mode is active, which email
npx sheetcraft-mcp@latest auth logout   # delete stored tokens

Switching accounts: run auth logout first — auth login refuses to overwrite an existing session otherwise (pass --force to override).

Option B: Service account — edit-only on shared files

  1. In Cloud Console: create a service account, create a JSON key for it, enable the Sheets API.

  2. Point the server at the key:

export GOOGLE_SERVICE_ACCOUNT_CREDENTIALS="$(cat service-account.json)"
# or: export GOOGLE_SERVICE_ACCOUNT_FILE=/path/to/key.json
  1. Share spreadsheets with the SA's email like any collaborator. It can read and edit but cannot create files — use OAuth for that.

Which mode wins

If both are configured: SHEETS_AUTH_MODE=oauth|service-account forces a mode; otherwise service-account env credentials win, then stored OAuth tokens.

Your OAuth app stays in "Testing" mode until Google verifies it. Expect these two screens:

What you see

What it means

Fix

"Access blocked … Error 403: access_denied"

The Google account you're logging in with is not a test user of your own app

Cloud Console → APIs & Services → OAuth consent screen → Audience / Test users → Add users → add that account. Takes effect immediately.

"Google hasn't verified this app" warning

Normal for your own unverified app

Advanced → Go to <app name> (unsafe) → Allow

If you'd rather not touch the consent screen at all, use a service account.


MCP configuration

OpenCode

// opencode.json
{
  "mcp": {
    "sheets": {
      "type": "local",
      "command": ["npx", "-y", "sheetcraft-mcp@latest"],
      "environment": {
        "SHEETS_TOOLSETS": "core,drive"
      },
      "enabled": true
    }
  }
}

Gate destructive tools in agent config so the agent asks before acting:

{ "tools": { "sheets_delete_sheet": "ask", "sheets_batch_update": "ask", "sheets_trash_spreadsheet": "ask" } }

Claude Desktop / any standard MCP client

{
  "mcpServers": {
    "sheets": {
      "command": "npx",
      "args": ["-y", "sheetcraft-mcp@latest"],
      "env": { "SHEETS_TOOLSETS": "core,drive" }
    }
  }
}

Notes for all clients:

  • OAuth login done via the CLI is picked up automatically (same token store) — configure the server first, log in after, no restart dance needed.

  • The tool prefix comes from your config key: "sheets"sheets_get_values, sheets_update_values, …

  • Credentials are never put in this config. The server reads them from ~/.config/sheetcraft-mcp/ (OAuth) or env vars (service account).


Toolsets

34 tools ship in 6 opt-in groups. Select with the SHEETS_TOOLSETS environment variable — default is core,drive.

Toolset

Tools

Register when the agent needs to…

core (default)

15

Read/write values, manage sheets/tabs, find & replace

drive (default)

7

Create/copy/search/share/trash/export spreadsheets

formatting

5

Style cells, merge, freeze, conditional formatting

charts

3

Create/edit/delete embedded charts

pivot

2

Build pivot tables (see limitations)

power

2

Raw batchUpdate escape hatch + range sorting

all

34

Everything

SHEETS_TOOLSETS=core                     # 15 tools  (~4K tokens of schema)
SHEETS_TOOLSETS=core,drive               # 22 tools  (default)
SHEETS_TOOLSETS=core,drive,formatting,charts
SHEETS_TOOLSETS=all                      # 34 tools  (~10K tokens of schema)

Unknown names hard-fail at startup. Keep the list small — every tool's schema costs standing tokens in every conversation.


Tool catalog

Every data operation takes a spreadsheetId (bare ID, or paste a full URL — it's parsed), and sheet parameters accept a quoted name ('My Sheet') or gid:N. Every write echoes updatedRange/updatedCells. Every read is capped (default 5,000 cells) with an explicit truncation notice.

core — values and sheets (15)

Tool

What it does

Key parameters / defaults

get_values

Read a range. Returns CSV by default (most token-efficient)

format: csv · tsv · grid (2D JSON array) · records (header-joined objects)

batch_get_values

Read multiple ranges in one call

ranges — each result labeled with its A1

update_values

Write a 2D array to a range

input: USER_ENTERED (default — strings starting with = become formulas, dates parse) or RAW

batch_update_values

Write multiple ranges in one API call (one quota unit)

prefer over several update_values calls

append_rows

Append rows below the existing table (auto-detected)

default INSERT_ROWSnever overwrites rows below the table

clear_values

Clear values, keep formatting

destructive

get_spreadsheet_info

List tabs with titles, gids, dimensions, frozen state

call this first when all you have is a URL

add_sheet / delete_sheet / duplicate_sheet / rename_sheet

Tab management

delete is destructive; add_sheet accepts freezeRows/freezeCols

move_rows_columns

Move rows/columns to a new position in place — data, formatting, formulas move intact

the right way to reorder columns; never delete-and-recreate

insert_delete_dimensions

Insert/delete rows or columns

indices are 0-based (0 = first row/column)

find_replace

Find & replace across a sheet, range, or whole spreadsheet

replacement is required (omitting it would erase matches)

set_data_validation

Dropdowns (ONE_OF_LIST/ONE_OF_RANGE), checkboxes, number/text constraints; clearValidation=true removes rules

dropdown options via literal list or a range on an existing sheet

drive — file lifecycle (7)

Tool

What it does

Notes

create_spreadsheet

New empty spreadsheet

owned by whoever is logged in; in SA mode pass shareWith or it's invisible to humans

copy_spreadsheet

Copy data, formulas, formatting (not sharing)

find_spreadsheets

Search by name → candidate IDs, never auto-selected

sees files the authenticated identity can access

share_spreadsheet

Grant an account access

in SA mode, required after create_spreadsheet

trash_spreadsheet

Move to Drive trash (restorable)

permanent=true bypasses trash — cannot be undone

export_spreadsheet

Download whole file as xlsx / pdf / ods

per-sheet CSV: use get_values instead

resolve_target

Parse a URL → spreadsheetId + gid

also accepts bare IDs

formatting (5)

Tool

What it does

Notes

format_cells

Bold/italic/strikethrough, font size/color, background, number format, alignment, wrapping

only provided properties change; colors are #RRGGBB

merge_cells

Merge a range (ALL / COLUMNS / ROWS)

unmerge=true to undo

freeze_rows_columns

Sticky headers

pass 0 to unfreeze

conditional_format

Add/delete highlight rules

use get_formatting to find rule indices

get_formatting

Read formatting as run-length-encoded ranges + merges + rules

far cheaper than reading the full grid

charts (3)

Tool

What it does

Notes

create_chart

Embedded chart: COLUMN, BAR, LINE, AREA, SCATTER, COMBO, STEPPED_AREA

from a domain range + series ranges; returns chartId

update_chart

Change type, ranges, title, legend, stacking

patch semantics — fetch, merge, send

delete_chart

Delete by id

pivot (2) ⚠️

Tool

What it does

Notes

create_pivot

Grouped summaries (SUM/COUNT/AVERAGE/…) by row/column fields

Google's API silently drops pivot writes (verified; see limitations). The tool verifies persistence and warns honestly when the write didn't take

delete_pivot

Clear the cell holding the definition

power (2)

Tool

What it does

Notes

batch_update

Raw spreadsheets.batchUpdate — pass the API's requests array verbatim

covers banding, named ranges, protection, data validation, tables, slicers, and more; atomic (one bad request aborts the batch)

sort_range

Sort rows by one or more columns

the entire range sorts in place — exclude headers from the range


The CLI

The CLI runs the same 34 operations as subcommands — for scripting, piping, and bulk work. Same auth, same errors; any failure prints the same teaching message the MCP tools return and exits 1.

# discovery
npx sheetcraft-mcp@latest list                  # all 33 ops by toolset
npx sheetcraft-mcp@latest help get_values       # one op's full JSON schema

# operations — args as key=value pairs
npx sheetcraft-mcp@latest resolve_target url="https://docs.google.com/spreadsheets/d/…/edit"
npx sheetcraft-mcp@latest get_values spreadsheetId=<id> range="'My Sheet'!A1:D10"
npx sheetcraft-mcp@latest get_values spreadsheetId=<id> range="'My Sheet'!A1:D10" format=records

# structured output and stdin JSON (for 2D arrays with quotes/formulas)
npx sheetcraft-mcp@latest get_values spreadsheetId=<id> range=A:D --json | jq .
npx sheetcraft-mcp@latest append_rows spreadsheetId=<id> sheet=Data --stdin-json < rows.json

Flag

Purpose

--json

Force JSON output (reads print compact text by default)

--stdin-json

Read the whole args object as JSON from stdin — the safe way to pass rows containing quotes, apostrophes, newlines, or formulas

Auth: sheets auth login [--client <path>], sheets auth status, sheets auth logout. Every op is also available as sheets <op> … when installed globally.

Reads compose with standard tooling; writes are better done through MCP tools (the agent UI handles quoting and permission gating for you).

Agent skill

The npm package bundles a skill that teaches agents the CLI conventions (quoting, stdin JSON, exit codes, pitfalls) without trial and error:

# Claude Code:
ln -s "$(npm root -g)/sheetcraft-mcp/skills/managing-google-sheets" \
      ~/.claude/skills/managing-google-sheets

# OpenCode (`skill`, singular):
cp -r "$(npm root -g)/sheetcraft-mcp/skills/managing-google-sheets" \
      ~/.config/opencode/skill/managing-google-sheets

Environment variables

Variable

Purpose

Default

SHEETS_TOOLSETS

Which toolsets register: core, drive, formatting, charts, pivot, power, all, or a comma list

core,drive

GOOGLE_SERVICE_ACCOUNT_CREDENTIALS

Service-account key JSON (raw)

GOOGLE_SERVICE_ACCOUNT_FILE

Service-account key JSON (path)

SHEETS_AUTH_MODE

Force oauth or service-account

auto-resolved

GOOGLE_OAUTH_CLIENT_ID / GOOGLE_OAUTH_CLIENT_SECRET

OAuth client values (alternative to the client JSON file)

SHEETS_OAUTH_CLIENT_FILE

Custom path to the OAuth client JSON

~/.config/sheetcraft-mcp/oauth-client.json

GOOGLE_OAUTH_TOKEN_FILE

Custom token-store path

~/.config/sheetcraft-mcp/oauth-tokens.json

SHEETS_MAX_CELLS

Read cap per call

5000

SHEETS_RETRY_ATTEMPTS / SHEETS_RETRY_BASE_MS / SHEETS_RETRY_MAX_MS

Retry tuning for 429/5xx/network errors (exponential backoff + jitter)

3 / 300 / 8000

Troubleshooting

Symptom

Cause / fix

Tool call returns "No credentials configured"

Nothing is set up yet. Run npx sheetcraft-mcp@latest auth login, or set service-account env vars. The message lists both options verbatim

auth login → browser → "Access blocked / 403 access_denied"

Your account isn't a test user of your own OAuth app → add it under OAuth consent screen → Test users (see consent-screen gotchas)

"Already logged in as …" when switching accounts

Run auth logout first, or pass --force

Sheet "Data 2" not found. Sheets: "Sheet1"(gid:0), …

Teaching error — quote names with spaces: 'My Sheet'!A1:B2

Write landed in the wrong place

append_rows inserts below the table (never overwrites); update_values writes exactly the range you name — check updatedRange in the echo

find_replace erased text

replacement was empty/omitted. It's required for this reason

Sorting scrambled headers

sort_range sorts the whole range — exclude the header row from the range

Agent says a parameter "doesn't exist" or recalls a tool failing

Its tool list/schema may be stale (server updated mid-session). Re-check with help <op> / a fresh tools list — and never work around tools by reading the token store; that's out of bounds

Known limitations

  • Pivot tables via the API are unreliable — Google's API accepts the write but silently drops the definition (verified 2026-08-28, re-verified 2026-08-29 against Google's own documented request shape). create_pivot verifies persistence and warns when the write didn't take. For summaries, prefer get_values + update_values.

  • Cells in Google Tables (typed columns) reject data validation — if a tab is a Google Table (column chips with types), set_data_validation on its columns fails with "This operation is not allowed on cells in typed columns" (Google blocks it in the UI too). Use the table's column-chip menu in the UI instead, or convert the table to a normal range first.

  • Service accounts cannot create files — Google policy (0-byte storage quota). Use OAuth for create_spreadsheet / copy_spreadsheet.

  • Drive CSV export covers only the first sheet — use get_values for per-sheet CSV.

  • update_values writes in ROWS orientation — arrays are row-major.

Design notes for agent reliability

  • ID-first — every op takes spreadsheetId (full URLs parsed); sheet params accept 'Name' or gid:N.

  • Errors teach — bad ranges quote an example and list available sheets; rate-limit errors say that retries already happened.

  • Reads are cappedSHEETS_MAX_CELLS with an explicit notice telling the model how to get the rest.

  • Batching is encouragedbatch_update_values / batch_update = one API call per quota unit.

  • Cell contents are data, not instructions — sheet content is never echoed into error messages or prompts.

  • Retry + backoff built in — 429/5xx/network errors retry with exponential backoff + jitter before surfacing.

License

MIT — see LICENSE.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides a secure bridge for AI assistants to interact with the Google Sheets API via 31 tools for spreadsheet management, data manipulation, and table-level operations. It supports both Service Account and OAuth 2.0 authentication for tasks including batch updates, CSV imports, and conditional formatting.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to create, read, update, and manage Google Sheets data and structure using tools like create, listSheets, sheetData, updateCells, and shareSpreadsheet, supporting OAuth2 and service-account authentication.
    9,710 npm
    18
    MIT