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

@theethosteam/sheets-mcp

v0.1.1

Published

Full-control MCP server (and CLI) for Google Sheets — values, structure, formatting, charts and the complete batchUpdate surface over OAuth, plus Drive lifecycle (find, create, share, move). Runs via npx, locally or in cloud.

Downloads

85

Readme

@theethosteam/sheets-mcp

Full-control Google Sheets MCP server + CLI. Values, tabs, rows/columns, formatting, data validation, conditional formats, named ranges, the complete batchUpdate surface — plus the Drive half nobody remembers they need (find a spreadsheet by name, create one, share it, file it in a client folder).

Runs three ways from one registerTools():

  • remote custom connectorhttps://mcp.theethosteam.com/api/sheets/mcp (see apps/connectors-mcp), available in every Claude surface;
  • stdio MCP servernpx -y @theethosteam/sheets-mcp;
  • CLInpx -y -p @theethosteam/sheets-mcp sheets <command>.

Env

| Var | Required | Notes | |---|---|---| | SHEETS_OAUTH_CLIENT_ID | ✅ | Shared Ethos OAuth client | | SHEETS_OAUTH_CLIENT_SECRET | ✅ | | | SHEETS_OAUTH_REFRESH_TOKEN | ✅ | Must carry the spreadsheets + drive scopes | | SHEETS_SPREADSHEET_ID | — | Optional per-call default; every tool also takes an ID or a URL |

Auth

Same shared OAuth client as GA4/GTM/GSC/Ads, but the Sheets scopes are new — a refresh token minted before this connector existed will 403 on every call until you re-consent:

npx -y -p @theethosteam/google-ads-mcp ads auth:url        # requests ALL connector scopes
npx -y -p @theethosteam/google-ads-mcp ads auth:exchange <code>
# or, scoped to Sheets only:
npx -y -p @theethosteam/sheets-mcp sheets auth:url
npx -y -p @theethosteam/sheets-mcp sheets auth:exchange <code>

Why full drive and not drive.file. The Sheets API can only act on a spreadsheet whose ID you already hold. Finding one by name, sharing it, moving it, trashing it — all Drive. drive.file only ever sees files this OAuth client itself created, which excludes essentially every spreadsheet a human made by hand. Full drive is what makes "full control of Google Sheets" true.

The two things that make this usable

1. IDs, URLs and tab names all work. Every tool takes the spreadsheet as an ID or a pasted docs.google.com/spreadsheets/d/… URL, and takes a tab as its title ("Invoices") or its numeric sheetId. Omit the tab and you get the first one.

2. A1 in, GridRange out. A1 notation is 1-based and inclusive; the GridRange that batchUpdate wants is 0-based and end-exclusive. Getting that wrong doesn't error — it silently formats, sorts or deletes the wrong row. Every structural tool here takes A1 ("A1:D50", "B:D", "2:10") and does the conversion once, correctly. insert_rows_or_columns / delete_rows_or_columns likewise take 1-based, inclusive indices that match the numbers in the UI.

Write safety

Destructive and outward-facing operations fail closed without confirm:true: clear_range, delete_sheet, delete_rows_or_columns, delete_named_range, trash_spreadsheet, find_replace, share_spreadsheet — and batch_update whenever the payload contains a destructive request type (deleteSheet, deleteDimension, deleteRange, cutPaste, …). Everything else runs directly.

Tools (34)

Discoverysheets_whoami · list_spreadsheets · get_spreadsheet · list_sheets

Readread_range · read_ranges · export_csv

Writewrite_range · write_ranges · append_rows · clear_range🔒

Spreadsheet lifecyclecreate_spreadsheet · share_spreadsheet🔒 · list_permissions · move_spreadsheet · trash_spreadsheet🔒

Tabsadd_sheet · delete_sheet🔒 · duplicate_sheet · update_sheet_properties · copy_sheet_to

Rows & columnsinsert_rows_or_columns · delete_rows_or_columns🔒 · auto_resize · sort_range

Formatting & rulesformat_cells · merge_cells · set_data_validation · add_conditional_format · find_replace🔒

Named rangesadd_named_range · delete_named_range🔒

Escape hatchesbatch_update (every request type the API has) · raw (any method by dotted path; prefix drive: for Drive)

🔒 = requires confirm:true.

format_cells is additive — it builds a precise field mask from the properties you pass, so setting a background colour doesn't wipe existing bold, borders or number formats.

CLI

sheets whoami
sheets ls "Q3"                                  # find spreadsheets by name
sheets tabs <spreadsheet>                       # tab titles + sheetIds
sheets read "Invoices!A1:D50" -s <spreadsheet>
sheets read "A1:D50" -s <spreadsheet> --csv
sheets append '[["Acme",1200]]' -s <spreadsheet> -t Invoices
sheets write "A1:B2" '[["a",1],["b",2]]' -s <spreadsheet>
sheets create "Q4 Budget" --tabs Oct,Nov,Dec
sheets batch '[{"addSheet":{"properties":{"title":"New"}}}]' -s <spreadsheet>
sheets raw spreadsheets.values.get '{"spreadsheetId":"…","range":"A1:B2"}'

Anything not covered by a named tool

batch_update reaches the entire Sheets API write surface — charts, pivot tables, banding, protected ranges, filter views, dimension groups, developer metadata, borders. raw reaches the read side, including spreadsheets.getByDataFilter and spreadsheets.developerMetadata.search, and Drive via a drive: prefix. There is no operation this connector cannot do.