DataLatte
MCP + Google Sheets: AI That Reads and Writes Your Bookings Spreadsheet
AI Automation

MCP + Google Sheets: AI That Reads and Writes Your Bookings Spreadsheet

June 13, 2026·Nataliia· 10 min read All posts
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 --version to 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.
  1. Go to Google Cloud Console and create a new project (name it something like sheets-ai-agent)
  2. Go to APIs & Services → Enable APIs and enable Google Sheets API
  3. Go to APIs & Services → Credentials and click Create Credentials → Service Account
  4. Name the service account ai-agent and click through the rest
  5. On the service account page, go to Keys → Add Key → Create new key → JSON
  6. Download the JSON file and save it as credentials.json in 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.
Before adding AI, organize your spreadsheet with these sheets (tabs):
Sheet 1: Appointments
DateTimeClient NamePhoneServiceStaffDurationPriceStatusNotes
2026-06-1610:00Maria Chen+1-555-0123Haircut + ColorSarah90120.00Confirmed
2026-06-1614:00Tom Wilson+1-555-0456Beard TrimMike3025.00ConfirmedFirst visit
Sheet 2: Clients
PhoneNameEmailVisit CountLast VisitPreferencesNotes
+1-555-0123Maria Chenmaria@email.com122026-05-30No sulfatesDeep conditioning loyal
Sheet 3: Revenue
Week StartAppointmentsRevenueAvg TicketNo-ShowsNo-Show Rate
2026-06-09473840.0081.7036.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

FeatureAI + Google SheetsCalendlyVagaroManual Sheets (No AI)
Monthly cost$0 (gspread free)$20–$49/month$30/month$0
Booking automationYes (with scripts)Yes (native)Yes (native)No
AI-powered insightsYesNoBasic reportsNo
CustomizationFull (your schema)LimitedModerateFull
Client self-booking portalNo (need add-on)YesYesNo
Existing data migrationNone neededRequiredRequiredN/A
No-show trackingYes (custom)YesYesManual
Revenue reportsYes (custom)BasicYesManual
Setup time2–4 hours30 min1 hourAlready done
Best forOwners who love SheetsSimple online bookingFull salon softwareSmall 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.

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.

Learn more
Nataliia — local marketing expert
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 Nataliia

Want this applied to your business?

Let's review your current marketing setup together — free, no obligations.

Get Your Free Marketing Audit