npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@simon-bouchard/google-sheets-mcp

v0.3.0

Published

A local, stdio-based MCP server for reading, editing and formatting existing Google Sheets.

Readme

google-sheets-mcp

Status: early. Tools are unit-tested and live-verified against a real Google Sheet, but expect rough edges.

A local, stdio-based MCP server that lets Claude Code (or any MCP client) read, edit and format existing Google Sheets. It authenticates as a Google Cloud service account, or, once the Koios OAuth client exists, as you after a one-time browser sign-in. Sibling project of google-docs-mcp, with the same auth model.

Setup

  1. Create a Google Cloud project (or reuse the one from google-docs-mcp).

  2. Enable the Google Sheets API for that project (APIs & Services -> Library -> "Google Sheets API" -> Enable). Enabling the Docs API does not cover Sheets. If you skip this, every call fails with a SERVICE_DISABLED 403, which reads like "the sheet isn't shared with me" but is not.

  3. Create a service account (IAM & Admin -> Service Accounts), or reuse an existing one. It needs no project roles: its access comes entirely from sharing.

  4. Install its JSON key:

    mkdir -p ~/.config/google-sheets-mcp
    cp <your-key>.json ~/.config/google-sheets-mcp/service-account.json
    chmod 600 ~/.config/google-sheets-mcp/service-account.json

    Set GOOGLE_SHEETS_MCP_CONFIG_DIR to use a different directory.

  5. Share each spreadsheet with the service account's email (<name>@<project>.iam.gserviceaccount.com) as Editor (or Viewer for read-only use).

  6. Send that email to the maintainer so it can be added as an editor of the shared feedback spreadsheet (used by both servers). Without it, automatic issue reports from your sessions fail silently.

Signing in with your Google account (not yet available)

A second auth mode is built in: sign in once in the browser and the server acts as you, seeing exactly the files you can see, with no key file or sharing step. It waits on a Koios Workspace admin creating the Internal OAuth client; until then, use the service account above. Both modes can stay installed side by side.

  1. Get the OAuth client (a Desktop app client in a Koios-owned Cloud project) and save its JSON at ~/.config/google-workspace-mcp/oauth-client.json, or set GOOGLE_WORKSPACE_MCP_CLIENT_ID (and GOOGLE_WORKSPACE_MCP_CLIENT_SECRET). Once the Koios client exists it will ship with the package and this step goes away.

  2. Sign in:

    npx -y @simon-bouchard/google-sheets-mcp login

    The browser opens Google's consent page; the token is saved at ~/.config/google-workspace-mcp/token.json (mode 600). The sign-in is shared with google-docs-mcp, so signing in through either server covers both.

  3. Restart Claude Code so the server picks up the sign-in.

Which mode is used: a saved sign-in wins over a service account key. Set GOOGLE_SHEETS_MCP_AUTH=service_account (or oauth) to force one, for example to go back to the service account without signing out. npx -y @simon-bouchard/google-sheets-mcp logout deletes the saved token; to also revoke access, remove the app at https://myaccount.google.com/connections. When signed in, issue reports are written as you, so the feedback spreadsheet must be editable by you rather than by a service account.

GOOGLE_WORKSPACE_MCP_CONFIG_DIR moves the shared directory.

Installing as a Claude Code plugin

claude plugin marketplace add https://bitbucket.org/koiosemployee/google-sheets-mcp.git
claude plugin install google-sheets-mcp

This registers the server and adds the /google-sheets-mcp:feedback command. Or register only the server:

claude mcp add --scope user google-sheets -- npx -y @simon-bouchard/google-sheets-mcp

Tool permissions go in ~/.claude/settings.json. Tool names are mcp__<server name>__<tool>, so with the command above (server name google-sheets):

  • To be prompted before every change to your sheets, add mcp__google-sheets__write_cells, mcp__google-sheets__append_rows, mcp__google-sheets__clear_range and mcp__google-sheets__edit_spreadsheet to permissions.ask.
  • For automatic issue reports to really happen in the background, add mcp__google-sheets__report_issue to permissions.allow; otherwise Claude Code stops to ask for permission the first time a report is filed. Run /mcp to see the exact server name if you installed it as a plugin.
{
  "permissions": {
    "allow": ["mcp__google-sheets__report_issue"],
    "ask": ["mcp__google-sheets__edit_spreadsheet"]
  }
}

Tools

  • get_spreadsheet: the spreadsheet's title and its tabs (title, sheetId, grid size, frozen row and column counts).
  • read_range: cell values of an A1-notation range, row-major. render: "formula" returns each cell's formula instead of its displayed value; read this way before overwriting cells that might hold formulas. include_format: true also returns formats (each cell's format, in format_cells' attribute names, null when unformatted), merges, validations (each cell's dropdown), and conditional_formats (every rule touching the range, in priority order). It reads at most 2,000 cells and needs a range that names its tab.
  • write_cells: overwrite one or more ranges in a single call. Each update can carry an expected grid (the values read_range returned): if any guarded range has changed since, the whole call is refused with stale_value and nothing is written. The check and the write are two API calls, so a change landing between them isn't caught; the guard is for "someone edited the sheet since Claude last read it", not for high-contention writes.
  • clear_range: clear the values of one or more ranges, keeping their formatting.
  • append_rows: append rows after the last row of the table in a range. Inserts new rows, never overwrites.
  • edit_spreadsheet: structure and formatting, applied atomically (all or nothing). Operations run in order and each sees the ones before it: after insert_rows before row 5, the old row 5 is row 6 for later operations. Every range names its tab ("Tab!B2:D10", rows "Tab!3:5", columns "Tab!C:D", whole tab "Tab"); quote titles with spaces or that look like a cell ("'My Tab'!A1", "'Q1'!A1").
    • Structure: add_sheet, rename_sheet, delete_sheet, duplicate_sheet, insert_rows, insert_columns, delete_rows, delete_columns, freeze.
    • Formatting: format_cells (bold, italic, underline, strikethrough, font, size, text and background color, alignment, wrap, number format; sets only what you pass), clear_format, set_borders, set_column_width, set_row_height, auto_resize, merge_cells, unmerge_cells.
    • Dropdowns: set_dropdown (a fixed list of options, or an options_range whose cells hold the choices; strict by default) and clear_validation. Strictness only applies to people editing in the UI: Google does not check API writes against it.
    • Conditional formatting: add_conditional_format (a condition such as text_eq, number_less, date_before or custom_formula, formatting with bold, italic, strikethrough, text or background color), add_color_scale (min / optional mid / max colors), and clear_conditional_formats, which removes rules lying entirely inside a range and reports (in notes) any that extend outside it. New rules go on top, so they win where rules overlap. A clear must come before row/column inserts or deletes on the same tab in one call.
    • Takes the same optional expected guard as write_cells, checked before anything is sent.
    • Not supported yet: editing or reordering one conditional rule, other data validation (numbers, dates, checkboxes), charts, filters, sorting, protected ranges, alternating colors.
  • report_issue: files a bug or limitation of this server to the maintainers' feedback spreadsheet, in the background (see Automatic issue reports).

write_cells and append_rows default to RAW input, so a value starting with = is stored as text, not evaluated. Pass value_input_option: "USER_ENTERED" to have formulas and dates parsed as if typed into the UI. In write_cells it can also be set on a single update, so one call can write formulas in some ranges while keeping untrusted text literal in the others; the call stays atomic. Check formulas with read_range: the default render shows the result (or an error such as #REF!), and render: "formula" shows the formula itself.

Errors come back as <code>: <message> with one of auth_required, not_found, invalid_range, invalid_request, stale_value, rate_limited, or internal_error.

Automatic issue reports

When the server hits one of its own bugs (an unexpected internal_error), the error tells Claude to file it in the background with report_issue, and the server attaches what Claude can't see: its version, the failed call's operations and the stack trace. Claude also files, following the server's instructions, when Google rejects a batch it checked was valid, when a call succeeded but did something other than what was asked (a read-back shows it, or you point it out; Claude reports even when unsure whose fault it is), or when you ask for a Google Sheets task that none of this server's tools can do (a limitation). Those reports carry the server's last three calls, reduced the same way as below, so the maintainers see what was actually sent.

Never reported: errors that are working as designed (the stale_value guard, fixable input errors), setup problems (auth, sharing, rate limits), network problems and Google outages, and requests meant for other tools or servers.

Reports go to the maintainers' feedback spreadsheet, shared with google-docs-mcp (Bugs and Limitations tabs, Source column auto, Server column google-sheets-mcp), at most once per problem per session, and Claude mentions each one in a single line. What gets written is kept to what's needed to reproduce the problem:

  • The spreadsheet id is removed; cell values, dropdown options and condition values become their size ([3x2 values], [4 values]), and new tab titles their length. Ranges keep their tab names.
  • Claude describes cell or tab content instead of quoting it.
  • Credentials are scrubbed from every field before anything is written (tokens, keys, passwords, Authorization headers, OAuth client secrets, private keys, long random strings).

To turn it off, set GOOGLE_SHEETS_MCP_AUTO_REPORT=off. To let reports go through without a permission prompt, allow report_issue (see Installing).

Reporting feedback yourself

/google-sheets-mcp:feedback [bug|limitation] [notes] drafts a report from the conversation, shows it to you, and files it through report_issue after you confirm, even when automatic reports are turned off. Anything you write after the kind word is kept verbatim in Reporter notes, and the row's Source is manual with notes (or manual without notes).

Triaging reports

Both servers file into one spreadsheet. Each row stays there for good; its status is tracked in two columns maintainers fill in:

  • Status: a dropdown with in progress, fixed, won't fix and duplicate. Empty means new; those rows are tinted so they stand out.
  • Resolution: free text, e.g. fixed in 0.3.0 (ae34555) or duplicate of row 4.

To remove a report, delete its row rather than clearing its cells: a blank row splits the table, and later reports would then be inserted after the first block instead of at the end.

Maintainer setup (once): a spreadsheet with a Bugs tab whose first row is

Date | Source | Summary | Details | Steps to reproduce | Expected | Actual | Relevant errors | Reporter notes | Server | Status | Resolution

and a Limitations tab whose first row is

Date | Source | Summary | What was attempted | Workaround used | Details | Server context | Reporter notes | Server | Status | Resolution

shared as Editor with every user's service account (for both servers); then set DEFAULT_FEEDBACK_SHEET_ID in src/reporting.ts here and in google-docs-mcp. Users can override it with GOOGLE_SHEETS_MCP_FEEDBACK_SHEET_ID.

Roadmap

  • Ship the Koios OAuth client with the package. The sign-in mode is built; it needs a Koios Workspace admin to create an Internal OAuth client in a Koios-owned Cloud project. Once it exists, it goes into BUNDLED_OAUTH_CLIENT (src/oauth.ts, here and in google-docs-mcp) so signing in needs no client file. The service-account mode stays as a fallback.

Developing

npm install
npm run build
npm test

npm run dev runs the server from TypeScript source via tsx.

npm run smoke-test (with SHEETS_MCP_TEST_SPREADSHEET_ID set to a spreadsheet the service account can edit) runs every tool live inside a scratch tab it creates and then deletes.

Set SHEETS_MCP_TEST_REPORT_SPREADSHEET_ID to a scratch spreadsheet (never the real feedback one) to also exercise report_issue: the smoke test creates temporary Bugs and Limitations tabs there, files into them, and deletes them. It refuses if those tabs already exist.