Connect to any Google Spreadsheet. Each sheet tab becomes a table with auto-generated tools.
pip install mcp-maker[gsheets]- Go to Google Cloud Console
- Click the project dropdown (top left) → New Project
- Name it (e.g.,
mcp-maker) → Create
- In your project, go to APIs & Services → Library
- Search for Google Sheets API → click → Enable
- Search for Google Drive API → click → Enable
- Go to IAM & Admin → Service Accounts
- Click Create Service Account
- Name it (e.g.,
mcp-maker-bot) → Create and Continue - Skip the role selection → Continue → Done
- Click on your new service account
- Go to the Keys tab
- Add Key → Create new key → JSON → Create
- A JSON file downloads — save it somewhere safe (e.g.,
~/credentials/gsheets-sa.json)
- Open the downloaded JSON file
- Find the
client_emailfield — it looks like:mcp-maker-bot@your-project.iam.gserviceaccount.com - Open your Google Spreadsheet in the browser
- Click Share (top right)
- Paste the service account email
- Set permission to Viewer (or Editor if using
--read-write) - Click Send
This step is critical! The service account is treated as a separate user. It can only access spreadsheets explicitly shared with it.
export GOOGLE_SERVICE_ACCOUNT_FILE=/path/to/your-credentials.jsonFor permanent setup:
echo 'export GOOGLE_SERVICE_ACCOUNT_FILE=~/credentials/gsheets-sa.json' >> ~/.zshrc
source ~/.zshrcAlternative — JSON content directly (useful for deployment):
export GOOGLE_CREDENTIALS_JSON='{"type":"service_account","project_id":"my-project",...}'From the URL of your Google Sheet:
https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjiSfghkH/edit
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is your Spreadsheet ID
mcp-maker init gsheet://1BxiMVs0XRA5nFMdKvBdBZjiSfghkHfilter_{sheet}(field, value, operator)— eq/ne/gt/gte/lt/lte/contains filteringaggregate_{sheet}(group_by, agg_function, agg_column)— count/sum/avg/min/maxdistinct_{sheet}(field)— distinct values of a columnlist_{sheet}now supportssort_field/sort_direction(numeric-aware)- Fixed: sheets with duplicate or empty headers no longer break reads
- Fixed:
count_{sheet}counts actual data rows (it previously returned the grid size, often 1000)
For a spreadsheet with tabs Clients and Invoices:
| Tool | Example | What It Does |
|---|---|---|
list_clients(limit, offset, fields) |
list_clients(limit=20) |
→ {results, total, has_more, next_offset} |
search_clients(query, limit) |
search_clients(query="Acme") |
Search across all columns |
count_clients() |
count_clients() |
Total row count |
schema_clients() |
schema_clients() |
Column headers and inferred types |
export_clients_csv() |
export_clients_csv() |
Export as CSV string |
export_clients_json() |
export_clients_json() |
Export as JSON string |
Advanced list features:
list_clients(fields="name,email")→ Column selection
| Tool | Example | What It Does |
|---|---|---|
append_clients(name, email, ...) |
append_clients(name="Alice", email="a@co.com") |
Add a new row at the bottom |
update_clients_cell(row_number, field, value) |
update_clients_cell(row_number=5, field="status", value="Active") |
Update a single cell |
Each tab/sheet in your spreadsheet becomes a separate table:
Your Google Spreadsheet
├── Tab: "Clients" → Table: clients
├── Tab: "Invoices" → Table: invoices
├── Tab: "2024 Revenue" → Table: _2024_revenue
└── Tab: "Settings" → Table: settings
- Row 1 = column headers. The first row of each tab is used as field names.
- Row 2 onwards = data. These are your records.
- Tab names are sanitized — spaces become underscores, special chars are removed.
Tab: "Clients"
| Name | Company | Status | |
|---|---|---|---|
| Alice Johnson | alice@acme.com | Acme Corp | Active |
| Bob Smith | bob@globex.com | Globex Inc | Inactive |
| Carol Williams | carol@initech.com | Initech | Active |
Tab: "Invoices"
| Invoice # | Client | Amount | Paid |
|---|---|---|---|
| INV-001 | Acme Corp | 5000 | Yes |
| INV-002 | Globex Inc | 3200 | No |
| INV-003 | Initech | 7500 | Yes |
export GOOGLE_SERVICE_ACCOUNT_FILE=~/credentials/service-account.json
mcp-maker init gsheet://1BxiMVs0XRA5nFMdKvBdBZji --read-write
mcp-maker serveYou: "What clients do we have?"
Claude: calls
list_clients()"You have 3 clients: Alice Johnson (Active), Bob Smith (Inactive), and Carol Williams (Active)."
You: "Show me unpaid invoices"
Claude: calls
search_invoices(query="No")"There's 1 unpaid invoice: INV-002 for Globex Inc, $3,200."
You: "Add a new client: Dave Brown at MegaCorp, status Active"
Claude: calls
append_clients(name="Dave Brown", email="dave@megacorp.com", company="MegaCorp", status="Active")"Added Dave Brown to the Clients sheet."
You: "Mark Bob as Active"
Claude: First calls
list_clients()to find Bob's row number (row 3), then callsupdate_clients_cell(row_number=3, field="status", value="Active")"Updated Bob's status to Active."
Each record in results includes a row_number field:
[
{"row_number": 2, "name": "Alice Johnson", "email": "alice@acme.com", ...},
{"row_number": 3, "name": "Bob Smith", "email": "bob@globex.com", ...},
{"row_number": 4, "name": "Carol Williams", "email": "carol@initech.com", ...}
]- Row 1 is the header row
- Row 2 is the first data row
- Use
row_numberwithupdate_cellto update specific rows
MCP-Maker infers column types from your data:
| Data Pattern | Inferred Type | Example Values |
|---|---|---|
| Integers only | Integer | 1, 42, 1000 |
| Decimals | Float | 9.99, 3.14 |
| true/false/yes/no | Boolean | TRUE, FALSE |
| Everything else | String | "hello", dates, etc. |
For Google Sheets, you need to pass the credentials env var to Claude Desktop:
{
"mcpServers": {
"my-sheets": {
"command": "/usr/bin/python3",
"args": ["/full/path/to/mcp_server.py"],
"env": {
"GOOGLE_SERVICE_ACCOUNT_FILE": "/full/path/to/credentials.json"
}
}
}
}- Did you share the spreadsheet with the service account email?
- Open the JSON credentials file → copy
client_email→ Share the sheet with that email
Go to Google Cloud Console → APIs & Services and enable both the Google Sheets API and Google Drive API.
Make sure GOOGLE_SERVICE_ACCOUNT_FILE points to the actual file:
ls -la $GOOGLE_SERVICE_ACCOUNT_FILE # Should show the fileMake sure the spreadsheet is shared with Editor access (not just Viewer) for the service account.
- Make sure your sheet has data starting from row 1 (headers) and row 2 (data)
- Completely empty sheets are skipped