google-workspace-mcp
by adamkwhite
README.md
# Google Workspace MCP Server
A configurable Model Context Protocol (MCP) server that enables Claude to manage your Google Workspace services. **Choose which services to enable** - Calendar, Gmail, Docs, or any combination. Works with regular Gmail accounts - no Google Workspace subscription required!
[](https://sonarcloud.io/summary/new_code?id=adamkwhite_google-workspace-mcp)
[](https://sonarcloud.io/summary/new_code?id=adamkwhite_google-workspace-mcp)
[](https://sonarcloud.io/summary/new_code?id=adamkwhite_google-workspace-mcp)
[](https://sonarcloud.io/summary/new_code?id=adamkwhite_google-workspace-mcp)
[](https://sonarcloud.io/summary/new_code?id=adamkwhite_google-workspace-mcp)
[](https://sonarcloud.io/summary/new_code?id=adamkwhite_google-workspace-mcp)
## š§ User-Configurable Services
**You control which Google services are enabled:**
- ā
Mix and match: Enable only Calendar + Docs, or Gmail only, etc.
- š **Minimal permissions**: Only request access to services you actually use
- š **Easy changes**: Reconfigure anytime with interactive tool
- š”ļø **Secure**: No unnecessary broad permissions
## Features
### š
**Google Calendar**
- Create events with enhanced day-of-week calculations
- **š NEW**: Smart holiday detection and scheduling
- Automatically prevents scheduling on US and Canadian holidays
- Suggests alternative working days when holidays detected
- Optional force_holiday_booking parameter to override
- List calendars and events with **computed day-of-week information**
- Manage attendees and send invitations
- Search events by date or keywords
- Enhanced responses include accurate day-of-week, duration, and date calculations
### āļø **Gmail**
- Send emails with HTML support
- Search emails with Gmail's powerful query syntax
- Create drafts for later editing
- Support for CC/BCC recipients
- **šÆ NEW**: Label-based access restriction
- Optional filtering to restrict access to emails with specific label (e.g., "Jobs")
- When enabled: search_emails filters automatically, send/draft operations blocked
- Configurable via interactive setup or config/scopes.json
### š **Google Docs**
- Create documents with initial content
- Update existing documents with new content
- Organize in Drive folders
- Share with collaborators
### š **Google Sheets** (Not Implemented)
- Create spreadsheets with data
- Add headers and formatting
- Import data arrays
### š½ļø **Google Slides** (Not Implemented)
- Create presentations
- Add slides with different layouts
- Insert content
## Security & Design Principles
**š”ļø Safe-by-Design: Intentionally Limited Operations**
This MCP server follows the principle of least privilege by intentionally excluding destructive operations:
### ā
**Supported Operations:**
- **Read**: List calendars/events, search emails, view documents
- **Create**: New events, emails, drafts, documents
- **Update**: Modify existing documents
- **Send**: Send emails (with explicit user intent)
### ā **Intentionally Excluded:**
- **Delete**: No deletion of events, emails, or documents
- **Trash**: No moving items to trash
- **Permanent removal**: No irreversible data destruction
**Why?** This design provides an additional safety layer:
- Prevents accidental data loss through AI interaction
- Requires manual confirmation via Google UIs for destructive actions
- Aligns with security best practice: "AI can create and modify, humans confirm deletion"
- Reduces risk of unintended consequences from misunderstood prompts
**Manual Cleanup:** Test data created through the MCP server (calendar events, documents, emails) should be deleted manually through Google Calendar, Drive, or Gmail interfaces.
## Quick Start
### Prerequisites
- Python 3.11+
- Gmail account
- Google Cloud project (free)
### Setup (~15 minutes, mostly the one-time Google Cloud config)
1. **Clone and setup**:
```bash
git clone https://github.com/adamkwhite/google-workspace-mcp.git
cd google-workspace-mcp
./scripts/setup.sh
```
2. **Configure services** (choose which to enable):
```bash
python scripts/configure_scopes.py
```
3. **Set up Google Cloud** (the fiddly, one-time part). Everything below happens in the [Google Cloud Console](https://console.cloud.google.com). Console labels shift occasionally, but the flow is stable:
**a. Create a project** ā use the project picker at the top bar (or select an existing one). It's free.
**b. Enable the APIs you'll use** ā *APIs & Services ā Enabled APIs & services ā + Enable APIs and Services*, then enable each that matches your config:
- **Google Calendar API** (if Calendar enabled)
- **Gmail API** (if Gmail enabled)
- **Google Docs API** (if Docs enabled)
- **Google Drive API** (required whenever Docs is enabled)
**c. Configure the OAuth consent screen** ā *APIs & Services ā OAuth consent screen*:
- User type: **External**
- Provide an app name, your user support email, and a developer contact email. Everything else can stay blank.
- You do **not** need to add scopes here ā the server requests them at runtime from your `scopes.json`.
**d. Add yourself as a test user** ā in the consent screen's *Audience* / *Test users* section, add your own Gmail address. While the app is in **Testing** status, only listed test users can authenticate (this is the #1 cause of "Access blocked" errors).
**e. Create the OAuth client** ā *APIs & Services ā Credentials ā + Create Credentials ā OAuth client ID*:
- Application type: **Desktop app**
- Create it, then **Download JSON** and save the file as `config/credentials.json` in the repo.
> **Refresh-token note:** while the app stays in **Testing**, Google expires refresh tokens after ~7 days, so you'd re-authenticate weekly. To avoid that, set the publishing status to **In production** (*OAuth consent screen ā Publish app*). For personal, single-user use you can stay in production without going through Google's verification review.
4. **Configure Claude Desktop**:
Add to your Claude Desktop config, replacing `<ABSOLUTE_PATH_TO_REPO>` with the absolute path to your clone (e.g., `/home/you/Code/google-workspace-mcp`). On Windows Claude Desktop with WSL:
```json
{
"mcpServers": {
"google-workspace": {
"command": "wsl.exe",
"args": [
"-d", "Ubuntu",
"bash", "-c",
"cd <ABSOLUTE_PATH_TO_REPO> && source .venv/bin/activate && PYTHONPATH=<ABSOLUTE_PATH_TO_REPO>/src python src/server.py"
]
}
}
}
```
See `config/claude_desktop_config.json` for the template and `config/claude_desktop_config_alternative.json` for a bash-free alternative. On non-Windows hosts, drop the `wsl.exe` wrapper and call the venv Python directly.
5. **First run** opens a browser to grant access (only for enabled services). Because the OAuth app is your own and unverified, Google shows a **"Google hasn't verified this app"** screen ā click **Advanced ā Go to \<app name\> (unsafe)** and continue. This is expected; it's your app. The token is then cached in `config/token.pickle` and refreshed automatically.
## šÆ Enhanced Calendar Features
### Day-of-Week Accuracy
Calendar events now include computed fields that eliminate day-of-week calculation errors:
```json
{
"summary": "Team Meeting",
"start": {"dateTime": "2025-09-27T14:00:00-04:00", "timeZone": "America/Toronto"},
"end": {"dateTime": "2025-09-27T15:00:00-04:00", "timeZone": "America/Toronto"},
"computed": {
"startDay": "Saturday",
"endDay": "Saturday",
"startDate": "2025-09-27",
"endDate": "2025-09-27",
"duration": "1 hour",
"spansMultipleDays": false
}
}
```
**Benefits:**
- ā
**Accurate day-of-week** - No more "Friday the 27th" when it's actually Saturday
- ā° **Human-readable duration** - "2 hours 30 minutes" instead of manual calculation
- š
**Date consistency** - Reliable YYYY-MM-DD format
- š **Timezone-aware** - Proper handling of EST, PST, UTC, and DST transitions
## Usage Examples
### Calendar Management
```
"Schedule a team meeting tomorrow at 2 PM for 1 hour with john@example.com and jane@example.com"
"Schedule a planning session next week" (automatically avoids holidays)
"Book a meeting on December 25th" (prompts: "This is Christmas. Continue? y/n")
"Show me all meetings this week with day-of-week information"
"List my calendar events for next Monday"
"Search for events with 'project review' in the title"
```
### Email Operations
```
"Send an email to the team about the project update"
"Search for emails from John about the budget"
"Create a draft email for the monthly newsletter"
"Find all unread emails from this week"
```
### Document Creation
```
"Create a meeting notes document for today's standup"
"Make a project proposal document and share it with sarah@example.com"
"Generate a report template in my Reports folder"
```
### Integrated Workflows
```
"Schedule a project review meeting next Monday at 10 AM, create an agenda document, and email the invite to the team"
"Find all emails about Q4 planning and create a summary document"
"Create a presentation about our new feature and schedule a demo meeting"
```
## š§ Managing Service Configuration
### Interactive Configuration
```bash
# Run the configuration wizard
python scripts/configure_scopes.py
```
The interactive tool helps you:
- ā
See current configuration
- š§ Enable/disable services
- ā ļø Handle dependencies automatically
- šļø Clean up authentication tokens when needed
### Manual Configuration
`config/scopes.json` is gitignored (it's your local config). Copy the template
to create it, then edit ā the server also falls back to sensible defaults if the
file is absent:
```bash
cp config/scopes.example.json config/scopes.json
```
The template ships with a sample `gmail_settings.restricted_label` list
(note `_News Feed` ā multi-word labels are matched exactly and quoted
automatically). Replace those with your own Gmail labels, or delete the
`gmail_settings` block to leave Gmail unrestricted.
```json
{
"enabled_services": {
"calendar": true, # Enable Google Calendar
"gmail": false, # Disable Gmail
"docs": true, # Enable Google Docs
"drive": true # Auto-enabled (required for Docs)
},
"gmail_settings": {
"restricted_label": "Jobs" # Optional: Restrict Gmail to specific label
}
}
```
### Gmail Label Filtering
Restrict Gmail operations to emails with one or more specific labels:
**Configuration** (single label):
```json
{
"enabled_services": {
"gmail": true
},
"gmail_settings": {
"restricted_label": "Jobs"
}
}
```
**Configuration** (multiple labels ā reads from any of them):
```json
{
"gmail_settings": {
"restricted_label": ["Jobs", "_News Feed", "AI"]
}
}
```
Label names must match Gmail exactly (case-sensitive, including leading
underscores and spaces). Multiple labels are combined with OR, so
`search_emails` returns mail carrying any one of them. The interactive
`configure_scopes.py` wizard only sets a single label ā for a list, edit
`config/scopes.json` directly.
**Behavior**:
- ā
**search_emails**: Automatically filters to only show emails with the configured label(s)
- š« **send_email**: Blocked with clear error message
- š« **create_email_draft**: Blocked with clear error message
**Use Cases**:
- Job search: Only access emails related to job applications
- Client communications: Restrict to specific client label
- Privacy: Limit AI access to subset of emails
**Setup**:
1. Create label in Gmail (e.g., "Jobs")
2. Run `python scripts/configure_scopes.py` and enable Gmail label filtering
3. Or manually add `gmail_settings` to `config/scopes.json`
4. Restart MCP server
### Checking Configuration
In Claude, use: `get_mcp_configuration` to see:
- Which services are enabled
- Required API scopes
- Configuration errors
- Available tools
## Available Tools (Conditional)
**Note**: Only tools for enabled services are available
### Configuration Tools (Always Available)
- `get_mcp_configuration` - Show current service configuration
### Calendar Tools (if enabled)
- `create_calendar_event` - Create new events with computed day-of-week fields
- `list_calendars` - Show all available calendars
- `list_calendar_events` - Search and list events with enhanced date information
### Gmail Tools (if enabled)
- `send_email` - Send emails with HTML support
- `search_emails` - Search with Gmail query syntax
- `create_email_draft` - Save drafts for later
### Document Tools (if enabled)
- `create_google_doc` - Create documents with content
- `update_google_doc` - Add content to existing documents
## Project Structure
```
google-workspace-mcp/
āāā config/
ā āāā scopes.example.json # Template ā copy to scopes.json
ā āāā scopes.json # Your service config (gitignored, user-editable)
ā āāā credentials.json # OAuth2 credentials from Google
ā āāā token.pickle # Cached authentication token
āāā src/ # Application source code
ā āāā server.py # Main MCP server (conditional tool registration)
ā āāā utils/
ā ā āāā scope_manager.py # Service configuration management
ā ā āāā date_helpers.py # Enhanced timezone-aware date calculations
ā āāā auth/
ā ā āāā google_auth.py # Dynamic authentication
ā āāā tools/ # Service-specific implementations
ā āāā calendar.py # Calendar operations
ā āāā gmail.py # Email operations
ā āāā docs.py # Document creation
āāā scripts/
ā āāā configure_scopes.py # Interactive configuration tool
āāā tests/ # Unit tests
āāā docs/ # Documentation
āāā scripts/ # Setup and deployment
āāā config/ # Configuration files
```
## Security
- OAuth2 authentication with secure token storage
- **User-configurable service permissions** - Enable only Calendar, Gmail, Docs, or any combination
- Minimal scope requests based on enabled services:
- Calendar: `https://www.googleapis.com/auth/calendar` (if enabled)
- Gmail: `https://www.googleapis.com/auth/gmail.modify` (if enabled)
- Docs: `https://www.googleapis.com/auth/documents`, `https://www.googleapis.com/auth/drive.file` (if enabled)
- Tokens stored locally, never transmitted
- Automatic token refresh
- All credentials in `.gitignore`
## API Quotas (Free Tier)
All quotas are per-user and more than sufficient for personal use:
- Calendar API: 1,000,000 queries/day
- Gmail API: 250 quota units/user/second
- Docs API: 300 requests/minute
- Sheets API: 300 requests/minute
- Slides API: 300 requests/minute
- Drive API: 1,000 requests/100 seconds
## Development
```bash
# Activate virtual environment
source .venv/bin/activate
# Run tests
pytest tests/
# Run server manually
python src/server.py
# Format code
black src/
```
## Troubleshooting
### Authentication Issues
- **"Access blocked: app not verified" / "app is being tested"** ā your Gmail isn't listed as a test user. Add it under *OAuth consent screen ā Test users*, or publish the app (see Setup step 3d).
- **Re-prompted to log in every ~7 days** ā the app is still in **Testing**; testing-mode refresh tokens expire weekly. Set publishing status to **In production** to stop this (Setup step 3).
- Delete `config/token.pickle` and re-authenticate
- Verify all APIs are enabled in Google Cloud Console
- Check `config/credentials.json` exists and is valid
### Permission Errors
- Ensure all required scopes are included
- Re-authenticate after adding new scopes
- Check API quotas haven't been exceeded
### Tool Errors
- Use `list_calendars` to get correct calendar IDs
- Verify email addresses are valid
- Check datetime formats (ISO 8601)
## Roadmap
- [x] Calendar integration with computed date fields
- [x] Gmail integration (send, search, drafts)
- [x] Google Docs creation and updates
- [x] User-configurable service scoping
- [ ] Calendar event updates and deletion
- [ ] Google Sheets with data import
- [ ] Google Slides with templates
- [ ] Batch operations
- [ ] Advanced search features
- [ ] File attachments
## Contributing
See [todo.md](todo.md) for current tasks and priorities.
## License
MIT
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues