AI Automation
MCP + Google Sheets: AI That Reads and Writes Your Bookings Spreadsheet
There's a reason so many local business owners run their bookings on Google Sheets. It's free. It works on any device. You can share it with your staff in seconds. Your accountant can access it without a subscription. And you built the exact columns you need — not whatever some $60/month booking software decided you should have.
The problem with Google Sheets isn't the tool. It's the manual work. Every booking means opening the sheet, finding the right row, typing in the details, double-checking availability, updating the client record. Do that 15 times a day and you've burned an hour on admin that should take five minutes.
MCP (Model Context Protocol) changes this. With the right setup, your AI agent can read your existing spreadsheet, check availability, log new bookings, flag no-shows, and generate weekly revenue reports — all without touching your current workflow or migrating to a new system.
Why Keeping Google Sheets Is Actually Fine
The tech industry loves to tell small business owners they need to "upgrade" from spreadsheets. That's often bad advice. Here's why staying on Google Sheets is a legitimate strategy:
- Zero cost: Google Sheets is free forever, unlike Calendly ($20+/month), Vagaro ($30+/month), or Fresha (commission on bookings)
- No lock-in: Your data is always yours, in a format every tool can import
- Familiar: Your staff already knows how to use it — no training required
- Flexible: You built it your way; every business has unique booking logic
- Shareable: Send a link and anyone can view (or edit, with permission)
MCP doesn't replace your spreadsheet. It adds intelligence on top of what you already have.
How MCP Bridges AI and Google Sheets
MCP is a protocol that lets AI models like Claude use external tools in a structured, secure way. When you connect a Google Sheets MCP server to Claude Desktop, the AI gains the ability to:
- Read cell ranges, entire sheets, and named ranges
- Write new rows, update existing cells
- Search for values (find a client by name)
- Format cells programmatically
The AI doesn't get raw access to your entire Google Drive — only the specific spreadsheet you authorize, with the specific permissions you grant.
Two Approaches: Choose What Fits Your Technical Level
Approach A: MCP Server for Claude Desktop (No Code Required)
This is the quickest path if you use Claude Desktop and want to work conversationally.
Prerequisites:
- Claude Desktop installed
- Google account
- Node.js installed (
node --versionto check)
Install the Google Sheets MCP server:
npm install -g @modelcontextprotocol/server-google-sheets
Add it to your Claude Desktop config at
~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):{
"mcpServers": {
"google-sheets": {
"command": "npx",
"args": ["@modelcontextprotocol/server-google-sheets"],
"env": {
"GOOGLE_SHEETS_CREDENTIALS_PATH": "path/to/your-credentials.json",
"GOOGLE_SHEETS_SPREADSHEET_ID": "YOUR_SPREADSHEET_ID"
}
}
}
}
The
YOUR_SPREADSHEET_ID is the long string in your spreadsheet URL: docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID/edit.Approach B: Python + gspread (For Custom Automation Scripts)
If you want scheduled automations — like a morning briefing that runs at 8am automatically — you need a script. The
gspread library is the standard Python way to interact with Google Sheets.pip install gspread google-auth anthropic
Both approaches use the same Google Sheets API credentials. Set those up first.
Setting Up Google Sheets API Access
This is a one-time 10-minute setup.
- Go to Google Cloud Console and create a new project (name it something like
sheets-ai-agent) - Go to APIs & Services → Enable APIs and enable Google Sheets API
- Go to APIs & Services → Credentials and click Create Credentials → Service Account
- Name the service account
ai-agentand click through the rest - On the service account page, go to Keys → Add Key → Create new key → JSON
- Download the JSON file and save it as
credentials.jsonin a safe location (NOT inside a public repo)
Your
credentials.json looks like this (with real values replaced by placeholders):{
"type": "service_account",
"project_id": "your-project-id",
"private_key_id": "YOUR_PRIVATE_KEY_ID",
"private_key": "-----BEGIN RSA PRIVATE KEY-----\nYOUR_PRIVATE_KEY_HERE\n-----END RSA PRIVATE KEY-----\n",
"client_email": "ai-agent@your-project-id.iam.gserviceaccount.com",
"client_id": "YOUR_CLIENT_ID",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token"
}
Finally, share your Google Sheet with the service account email (
ai-agent@your-project-id.iam.gserviceaccount.com) — give it Editor access. The AI agent will use this email to authenticate.Recommended Spreadsheet Structure
Before adding AI, organize your spreadsheet with these sheets (tabs):
Sheet 1: Appointments
| Date | Time | Client Name | Phone | Service | Staff | Duration | Price | Status | Notes |
|---|---|---|---|---|---|---|---|---|---|
| 2026-06-16 | 10:00 | Maria Chen | +1-555-0123 | Haircut + Color | Sarah | 90 | 120.00 | Confirmed | |
| 2026-06-16 | 14:00 | Tom Wilson | +1-555-0456 | Beard Trim | Mike | 30 | 25.00 | Confirmed | First visit |
Sheet 2: Clients
| Phone | Name | Visit Count | Last Visit | Preferences | Notes | |
|---|---|---|---|---|---|---|
| +1-555-0123 | Maria Chen | maria@email.com | 12 | 2026-05-30 | No sulfates | Deep conditioning loyal |
Sheet 3: Revenue
| Week Start | Appointments | Revenue | Avg Ticket | No-Shows | No-Show Rate |
|---|---|---|---|---|---|
| 2026-06-09 | 47 | 3840.00 | 81.70 | 3 | 6.4% |
Use named ranges in Google Sheets (Data → Named ranges) for each sheet range — this makes it much easier to reference them in code and MCP instructions.
5 Automation Workflows With Code
Workflow 1: Auto-Log New Bookings from WhatsApp or Email
When a client sends a WhatsApp message or email to book, your AI reads the message, extracts the booking details, and appends a new row to the Appointments sheet:
import gspread
from google.oauth2.service_account import Credentials
from datetime import datetime
def log_booking(client_name: str, phone: str, service: str,
date: str, time: str, price: float, staff: str = "TBD"):
"""Append a new booking row to the Appointments sheet."""
creds = Credentials.from_service_account_file(
"path/to/your-credentials.json",
scopes=["https://www.googleapis.com/auth/spreadsheets"]
)
gc = gspread.authorize(creds)
spreadsheet = gc.open_by_key("YOUR_SPREADSHEET_ID")
sheet = spreadsheet.worksheet("Appointments")
new_row = [
date, # Date
time, # Time
client_name, # Client Name
phone, # Phone
service, # Service
staff, # Staff
"", # Duration (fill in later)
price, # Price
"Confirmed", # Status
"" # Notes
]
sheet.append_row(new_row, value_input_option="USER_ENTERED")
return f"Booked: {client_name} for {service} on {date} at {time}"
Workflow 2: Morning Briefing — Today's Schedule via Slack
Set this to run automatically at 7:30am. It reads today's appointments and sends a summary:
import gspread
import anthropic
import requests
from google.oauth2.service_account import Credentials
from datetime import date
def send_morning_briefing():
creds = Credentials.from_service_account_file(
"path/to/your-credentials.json",
scopes=["https://www.googleapis.com/auth/spreadsheets"]
)
gc = gspread.authorize(creds)
sheet = gc.open_by_key("YOUR_SPREADSHEET_ID").worksheet("Appointments")
today = date.today().strftime("%Y-%m-%d")
all_rows = sheet.get_all_records()
today_rows = [r for r in all_rows if r.get("Date") == today]
if not today_rows:
schedule_text = "No appointments today."
else:
lines = []
for appt in sorted(today_rows, key=lambda x: x["Time"]):
lines.append(
f" {appt['Time']} — {appt['Client Name']} ({appt['Service']}, "
f"${appt['Price']}, Staff: {appt['Staff']})"
)
schedule_text = "\n".join(lines)
client = anthropic.Anthropic(api_key="YOUR_ANTHROPIC_API_KEY")
summary = client.messages.create(
model="claude-opus-4-5",
max_tokens=300,
messages=[{
"role": "user",
"content": f"Write a brief, friendly morning briefing for a salon owner. Today's schedule:\n{schedule_text}\nInclude total expected revenue and any notes to watch for."
}]
)
# Send to Slack
requests.post("YOUR_SLACK_WEBHOOK_URL", json={"text": summary.content[0].text})
send_morning_briefing()
Workflow 3: No-Show Tracker
At end of day, this script checks which confirmed appointments weren't marked "Completed" and flags them as no-shows:
def mark_no_shows():
creds = Credentials.from_service_account_file(
"path/to/your-credentials.json",
scopes=["https://www.googleapis.com/auth/spreadsheets"]
)
gc = gspread.authorize(creds)
sheet = gc.open_by_key("YOUR_SPREADSHEET_ID").worksheet("Appointments")
today = date.today().strftime("%Y-%m-%d")
all_records = sheet.get_all_records()
# Find confirmed appointments from today that weren't completed
no_shows = []
for i, row in enumerate(all_records, start=2): # row 1 is header
if row["Date"] == today and row["Status"] == "Confirmed":
sheet.update_cell(i, 9, "No-Show") # Column 9 = Status
no_shows.append(row["Client Name"])
return f"Marked {len(no_shows)} no-shows: {', '.join(no_shows)}"
Workflow 4: Weekly Revenue Report
Every Monday morning, calculate last week's numbers:
def weekly_revenue_report():
creds = Credentials.from_service_account_file(
"path/to/your-credentials.json",
scopes=["https://www.googleapis.com/auth/spreadsheets"]
)
gc = gspread.authorize(creds)
sheet = gc.open_by_key("YOUR_SPREADSHEET_ID").worksheet("Appointments")
revenue_sheet = gc.open_by_key("YOUR_SPREADSHEET_ID").worksheet("Revenue")
from datetime import timedelta
last_monday = date.today() - timedelta(days=date.today().weekday() + 7)
last_sunday = last_monday + timedelta(days=6)
all_records = sheet.get_all_records()
week_appts = [
r for r in all_records
if last_monday.strftime("%Y-%m-%d") <= r["Date"] <= last_sunday.strftime("%Y-%m-%d")
]
completed = [r for r in week_appts if r["Status"] == "Completed"]
no_shows = [r for r in week_appts if r["Status"] == "No-Show"]
total_revenue = sum(float(r["Price"] or 0) for r in completed)
avg_ticket = total_revenue / len(completed) if completed else 0
no_show_rate = len(no_shows) / len(week_appts) * 100 if week_appts else 0
new_row = [
last_monday.strftime("%Y-%m-%d"),
len(completed),
round(total_revenue, 2),
round(avg_ticket, 2),
len(no_shows),
round(no_show_rate, 1)
]
revenue_sheet.append_row(new_row)
return f"Week of {last_monday}: {len(completed)} appointments, ${total_revenue:.2f} revenue, {no_show_rate:.1f}% no-show rate"
Workflow 5: Availability Checker (Full Example)
A client asks "Is 3pm Tuesday free?" — the AI checks your sheet and answers instantly. This is the most impactful workflow for customer-facing AI:
import gspread
import anthropic
from google.oauth2.service_account import Credentials
from datetime import date, timedelta
def check_availability(query: str) -> str:
"""
Given a natural language availability query, check Google Sheets
and return a plain-English answer.
"""
creds = Credentials.from_service_account_file(
"path/to/your-credentials.json",
scopes=["https://www.googleapis.com/auth/spreadsheets"]
)
gc = gspread.authorize(creds)
sheet = gc.open_by_key("YOUR_SPREADSHEET_ID").worksheet("Appointments")
# Get all upcoming appointments
all_records = sheet.get_all_records()
today = date.today()
upcoming = [
r for r in all_records
if r.get("Date", "") >= today.strftime("%Y-%m-%d")
and r.get("Status") in ("Confirmed", "Pending")
]
# Build a booked-slots summary for the next 7 days
booked_summary = []
for r in upcoming:
booked_summary.append(f"{r['Date']} at {r['Time']} ({r['Service']}, {r['Duration']} min)")
booked_text = "\n".join(booked_summary) if booked_summary else "No upcoming bookings"
client = anthropic.Anthropic(api_key="YOUR_ANTHROPIC_API_KEY")
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=200,
system=f"""You are a booking assistant for a hair salon.
Business hours: Mon-Sat 9am-6pm, closed Sunday.
Each slot is 60 minutes minimum.
Today is {today.strftime('%A, %B %d, %Y')}.
Currently booked slots (next 7 days):
{booked_text}
Answer availability questions based on this data. Be specific: give a yes/no answer and suggest alternatives if the requested slot is taken.""",
messages=[{"role": "user", "content": query}]
)
return response.content[0].text
# Example
print(check_availability("Is 3pm this Tuesday free for a haircut?"))
# → "Tuesday 3pm is taken (we have Maria Chen booked 3pm-4:30pm).
# I have Tuesday at 10am, 1pm, or Wednesday at 3pm available. Which works for you?"
Comparison: This Setup vs Booking Platforms
| Feature | AI + Google Sheets | Calendly | Vagaro | Manual Sheets (No AI) |
|---|---|---|---|---|
| Monthly cost | $0 (gspread free) | $20–$49/month | $30/month | $0 |
| Booking automation | Yes (with scripts) | Yes (native) | Yes (native) | No |
| AI-powered insights | Yes | No | Basic reports | No |
| Customization | Full (your schema) | Limited | Moderate | Full |
| Client self-booking portal | No (need add-on) | Yes | Yes | No |
| Existing data migration | None needed | Required | Required | N/A |
| No-show tracking | Yes (custom) | Yes | Yes | Manual |
| Revenue reports | Yes (custom) | Basic | Yes | Manual |
| Setup time | 2–4 hours | 30 min | 1 hour | Already done |
| Best for | Owners who love Sheets | Simple online booking | Full salon software | Small volume |
The AI + Google Sheets approach wins on cost and flexibility. The tradeoff is setup time and the fact that clients can't self-book directly (unless you add a separate front-end form that feeds the sheet).
FAQ
Does this work with Google Workspace (paid Google accounts)?
Yes, and in some ways it works better. Google Workspace accounts have higher API quotas and you can set up shared drives that multiple staff members access. The setup process is identical — you still create a service account and share the sheet with it. The
credentials.json file and all the Python code above work exactly the same way.Is gspread free? Are there API limits?
Yes, gspread is a free, open-source Python library. The underlying Google Sheets API is also free, but has rate limits: 300 requests per minute per project, and 60 requests per minute per user. For a local business running a few automations per day, you will never come close to these limits. Even the morning briefing script that reads all records counts as a handful of API calls.
How do I protect sensitive columns from the AI?
The best approach is column-level access control through your Python code — simply don't include sensitive columns (like payment card details, if you store them) in what you read and pass to the AI. In the
get_all_records() call, you can select specific columns: sheet.get('A:F') gets only columns A through F, leaving G onwards out of reach. For the MCP server approach, configure it to expose only specific named ranges that exclude sensitive columns.Can the AI make mistakes in my spreadsheet?
Yes, it can — just like a human can mistype a row. Best practices: (1) Never give the AI delete permissions — only read and append. (2) Use Google Sheets version history (File → Version history → See version history) which lets you undo any change. (3) Test automations on a copy of your spreadsheet before running on the live version. (4) Have the AI log a human-readable record of every write operation so you can audit what it changed.
How do I undo AI edits?
Google Sheets automatically saves version history. Go to File → Version history → See version history to browse all changes with timestamps and authors. The service account email will appear as the "author" for AI-made changes. Click any version and hit Restore this version to roll back. For frequent automations, you can also build a simple undo mechanism by having your script append to a separate "Audit Log" sheet before making any change.
Related Articles
- What Is MCP? The Model Context Protocol Explained for Local Business Owners
- Claude + MCP + Google Calendar: Automate Your Booking Confirmations
- MCP + Supabase: Give Your AI Agent a Persistent Database
- MCP + Notion: Build a Client CRM for Your Local Business
- Best MCP Servers for Local Business: The Complete Setup Guide
Free for local businesses
Want this applied to your business?
I'll review your Google presence, local SEO, and ad accounts — and send you a specific action plan within 48 hours. No pitch, no pressure.
Want hands-on help?
See how DataLatte handles AI Agents & Automation for local businesses.

Nataliia
Local marketing strategist with 10+ years at global agencies — OMD, Dentsu, GroupM, and BBDO. Now helping small businesses get the same data-driven edge. Based in Europe, working with clients in the US, UK, Australia, and beyond.
About NataliiaRelated articles
AI Automation
AgentOps: Monitor and Debug Your Local Business AI Agents
9 min readAI Automation
AI Appointment Reminder Agent: Python Script That Cuts No-Shows by 40%
14 min readAI Automation
AI Agent for Google Reviews: Auto-Reply Script with Real Examples
13 min readAI Automation
AI Receptionist for Small Business: Complete Setup Guide 2026
12 min readWant this applied to your business?
Let's review your current marketing setup together — free, no obligations.
Get Your Free Marketing Audit