google-workspace-unlimited
This server provides AI assistants with comprehensive access to Google Workspace services through 90+ specialized MCP tools, combining management, content creation, search, and automation across Gmail, Drive, Docs, Sheets, Slides, Calendar, Forms, Chat, Photos, and People, enhanced with semantic memory, dynamic templating, and robust session controls.
Gmail: Search, send, draft, reply, forward emails with HTML or mixed content; download attachments; manage labels, filters, and trusted allowlists; compose dynamic responsive emails via DSL.
Drive: Upload files/folders, search with advanced filters, list contents, create files from URLs or content, share/set permissions, move/copy/rename/delete.
Docs: Search, read, create, and edit documents supporting Markdown, HTML, RTF, DOCX, LaTeX; advanced editing modes (replace all, insert at line, regex, append).
Sheets: List spreadsheets, get metadata, read/write/clear values, create new sheets, apply rich formatting (borders, colors, fonts, conditional rules, merging).
Slides: Create presentations, add slides, batch-update content, export to PDF, PPTX, PNG, etc.
Calendar: List/create calendars, manage events (single/bulk create, move, modify, delete), support recurring events and timezones.
Forms: Create forms, add/update questions, publish, list and retrieve responses.
Chat: List spaces/messages, send messages with markdown, manage members/reactions, send interactive cards via DSL (sections, buttons, carousels) or webhooks.
Photos: List albums, search/filter photos, upload single/batch/folders, create albums, sync optimizations, performance stats.
People: List contact groups/labels, resolve groups to member emails, manage contacts.
Semantic Memory (Qdrant): Vector search on tool history, fetch documents, usage analytics, and data cleanup.
Template System: Jinja2 macros for dynamic emails, cards, and reports; persist for reuse.
Management & Security: OAuth2.1 authentication, credential encryption, PII privacy masking, per-session tool enable/disable, code mode with meta-tools, health monitoring, x402 payment verification, and URL service filtering.
Provides 14 specialized tools for managing email workflows, including sending, replying, searching messages, and organizing them with labels and filters.
Offers comprehensive integration with the Google Workspace platform, enabling access to services such as Google Docs, Sheets, Slides, Forms, Chat, and Photos.
Features 9 tools for calendar management, supporting event creation, scheduling, attendee management, and timezone coordination.
Provides 9 tools for file management within Google Drive, including uploading, downloading, sharing files, and handling Office documents.
🚀 GoogleUnlimited Google Workspace Platform
GoogleUnlimited is a comprehensive MCP framework that provides seamless Google Workspace integration through an advanced middleware architecture. It enables AI assistants and MCP clients to interact with Gmail, Google Drive, Docs, Sheets, Slides, Calendar, Forms, Chat, Photos, and Contacts (People API) services using a unified, secure API.
What sets it apart:
⚡ Code Mode by default — instead of flooding your client with 90+ tool schemas, the server exposes 7 lightweight meta-tools; the AI discovers tools on demand and chains real API calls inside a single sandboxed
executeblock🚀 Zero-config startup — the server runs immediately with no
.envfile; OAuth happens lazily on first use🔧 Per-session tool control — URL-based service filtering and session-scoped enable/disable, so each connected client sees exactly the tools it needs
🎨 Template & card DSL system — Jinja2 macros and a compact card notation turn raw API data into rich emails, dashboards, and Google Chat cards
🧠 Semantic memory — every tool response is embedded into Qdrant, searchable later with natural language
📋 Table of Contents
Related MCP server: mcp-google-workspace
⚡ Quick Installation Instructions
What is GoogleUnlimited?
GoogleUnlimited provides AI assistants with access to Google Workspace services through the Model Context Protocol (MCP). It supports 92+ tools across 9 Google services, enabling seamless integration between AI workflows and Google Workspace applications with revolutionary performance improvements.
🛠️ Installation Methods
Method 1: Quick Install via uvx (Recommended)
The fastest way to get started - install directly from PyPI:
{
"mcpServers": {
"google-workspace-unlimited": {
"command": "uvx",
"args": ["google-workspace-unlimited"],
"disabled": false,
"timeout": 300
}
}
}⚡ That's it! The server runs in stdio mode by default, perfect for MCP clients like Claude Desktop, Cursor, Roo, etc. Code Mode is on out of the box, so your client sees 7 lean meta-tools instead of 90+ schemas.
Method 1b: Claude Code Plugin (server + skills)
Claude Code users can install the server and the skills that teach Claude its card/email DSL, code mode, and Qdrant search in two commands:
/plugin marketplace add dipseth/google_workspace_fastmcp2
/plugin install google-workspace-unlimited@riversunlimitedSee plugins/google-workspace-unlimited for details.
Method 2: Clone and Development Setup
For development or customization:
Clone and setup:
git clone https://github.com/dipseth/google_workspace_fastmcp2.git cd google_workspace_fastmcp2 uv syncStart the server:
uv run python server.pyThe server starts immediately with zero configuration required. OAuth credentials are not needed at startup — authentication is handled lazily when you first interact with a Google service.
Authenticate when ready:
When you call any Google Workspace tool, the server will prompt you to authenticate via the
start_google_authtool. This opens a browser-based OAuth flow. Once completed, credentials are stored locally and reused across sessions.To pre-configure OAuth credentials (optional), create a
.envfile:cp .env.example .envThen add your Google Cloud Console credentials:
# Option A: Client ID + Secret GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=your-client-secret # Option B: Downloaded JSON credentials file GOOGLE_CLIENT_SECRETS_FILE=credentials.jsonSee the Google Cloud Console setup steps for creating OAuth credentials and enabling APIs.
📚 Configuration Resources:
🔧 Complete Configuration Guide - Comprehensive environment variables and settings reference
🤖 Claude.ai Integration Guide - Setup for Claude.ai remote MCP server usage
🔒 HTTPS Setup Guide - SSL certificate configuration for secure connections
⚙️ MCP JSON Configuration Guide - Standard MCP configuration for any compatible client
📋 Environment Variables Reference
All environment variables are optional — the server starts with sensible defaults and no .env file required. OAuth credentials are only needed when initiating a new authentication flow via start_google_auth.
Google OAuth (needed for first-time authentication):
Variable | Default | Description |
| (empty) | OAuth 2.0 client ID from Google Cloud Console |
| (empty) | OAuth 2.0 client secret |
| (empty) | Alternative: path to downloaded OAuth JSON file |
|
| Must match Google Console redirect URI |
Provide either
GOOGLE_CLIENT_ID+GOOGLE_CLIENT_SECRETorGOOGLE_CLIENT_SECRETS_FILEbefore your first OAuth flow. Once authenticated, credentials are stored locally and these variables are no longer needed.
Server:
Variable | Default | Description |
|
| Server bind address |
|
| Server port |
|
| Enable HTTPS/SSL |
| - | Path to SSL certificate (required if HTTPS enabled) |
| - | Path to SSL private key (required if HTTPS enabled) |
|
|
|
Security & Sessions:
Variable | Default | Description |
|
|
|
|
| Directory for stored credentials |
| (empty) | Server API key — also used for crypto-bound credential encryption (HKDF-SHA256) and per-user key generation |
|
| Session idle timeout |
| (empty) | Comma-separated trusted email addresses |
Tool Management:
Variable | Default | Description |
|
| Start with only 5 protected tools enabled |
| (empty) | Comma-separated services to enable at startup (e.g., |
|
| Code Mode (default) — replaces the full tool catalog with 7 meta-tools + sandboxed |
|
| Enable FastMCP SkillsDirectoryProvider for dynamic skill generation |
|
| Directory for generated skill documents |
|
| Max tool response size in bytes (0 = disabled) |
| (empty) | Comma-separated tool names to limit (empty = all) |
Gmail Draft Preview Card:
Variable | Default | Description |
|
| Send a compact text summary instead of the card to clients showing no sign of MCP UI support |
|
|
|
|
| Fetch remote email images and inline them as |
Qdrant Vector Database:
Variable | Default | Description |
|
| Qdrant vector database URL |
|
| Qdrant API key (use |
|
| Auto-launch Qdrant via Docker if not reachable |
|
| Docker image for auto-launch |
|
| Container name for auto-launched Qdrant |
Other:
Variable | Default | Description |
| (empty) | Default webhook URL for Google Chat card tools |
|
| Enable cloud deployment mode (auto-switches to |
🔗 Client Connections
GoogleUnlimited supports multiple connection methods. Here are the two most popular ways to get started:
🎯 Quick Setup Options
Option 1: Cursor IDE (STDIO - Community Verified ✅):
{
"mcpServers": {
"google-workspace": {
"command": "uv",
"args": [
"--directory", "/path/to/google_workspace_fastmcp2",
"run", "python", "server.py"
],
"env": {
"GOOGLE_CLIENT_SECRETS_FILE": "/path/to/client_secrets.json",
"MCP_TRANSPORT": "stdio"
}
}
}
}Option 2: HTTP Streamable (VS Code Roo, Claude Code, Claude Desktop, etc.):
# Start server in HTTP mode
uv run python server.py --transport http --port 8002Basic single-connection config:
{
"google-workspace": {
"type": "streamable-http",
"url": "https://localhost:8002/mcp",
"disabled": false
}
}Multi-connection setup — connect the same client (or multiple clients) to the same server with different tool sets using URL query parameters:
{
"google-email": {
"type": "streamable-http",
"url": "https://localhost:8002/mcp?service=gmail"
},
"google-chat": {
"type": "streamable-http",
"url": "https://localhost:8002/mcp?service=chat"
},
"google-productivity": {
"type": "streamable-http",
"url": "https://localhost:8002/mcp?service=drive,docs,sheets,slides"
}
}Each connection gets its own isolated session with only the requested service tools enabled. You can also pin a session ID with ?uuid= to resume the same session state across reconnects:
{
"google-workspace": {
"type": "streamable-http",
"url": "https://localhost:8002/mcp?uuid=my-workspace&service=gmail,drive,calendar"
}
}See URL-Based Service Filtering for the full list of query parameters.
🤖 Claude Code & Claude Desktop
Claude Code (CLI) — one command, using the published PyPI package:
# Local stdio (recommended): uvx fetches and runs the server on demand
claude mcp add google-workspace -- uvx google-workspace-unlimited
# Or connect to an already-running HTTP server
claude mcp add --transport http google-workspace https://localhost:8002/mcpClaude Desktop (local dev path) — add to claude_desktop_config.json (Settings → Developer → Edit Config):
{
"mcpServers": {
"google-workspace-unlimited": {
"command": "uvx",
"args": ["google-workspace-unlimited"]
}
}
}Claude Desktop (bridge to a server you already run) — recommended when you keep a local HTTP server up for development. Every command entry starts its own copy of the server, and Cowork / Code sessions start a second one on top of that; when startup is slow (Qdrant hydration on a cold cache runs ~12s) the client gives up first and reports Couldn't start this server … Request timed out. Bridging to the already-warm server connects in about a second instead:
{
"mcpServers": {
"google-workspace-local": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://localhost:8002/mcp"],
"env": {
"NODE_EXTRA_CA_CERTS": "/path/to/mkcert/rootCA.pem"
}
}
}
}mcp-remote registers itself through the server's OAuth 2.1 dynamic client registration, opens a browser once, and caches the token under ~/.mcp-auth — no API key in the config file, and rotating MCP_API_KEY does not break it. NODE_EXTRA_CA_CERTS is only needed when the server uses a self-signed certificate (Node will not trust mkcert's CA otherwise); drop it if you terminate TLS with a public certificate.
Claude.ai / Claude Desktop (hosted connector) — run the server behind a public HTTPS endpoint (e.g. a Cloudflare or ngrok tunnel), then add it under Settings → Connectors → Add custom connector with your https://your-domain/mcp URL. The server's OAuth 2.1 + PKCE flow handles authentication, including the https://claude.ai/api/mcp/auth_callback redirect. See the Claude.ai Integration Guide for the full walkthrough.
📚 Complete Connection Guide
For detailed setup instructions, troubleshooting, and configurations for all supported clients including:
Claude Code CLI (HTTP & STDIO)
Claude Desktop
VS Code / Roo / GitHub Copilot
Claude.ai with Cloudflare Tunnel
And more...
🔗 Complete Client Connection Guide - Comprehensive setup instructions, troubleshooting, and advanced configurations for all supported AI clients and development environments
⚡ Code Mode (Default)
Code Mode is GoogleUnlimited's flagship feature — and it's on by default. Instead of loading 90+ tool schemas upfront (expensive on tokens), your MCP client sees just 7 meta-tools. The AI discovers tools on demand, then chains any number of real API calls inside a single sandboxed Python execute block.
Meta-Tool | Purpose |
| Browse tools by service category (Gmail, Drive, Calendar, etc.) |
| BM25-powered keyword search across tool names and descriptions |
| Get full parameter schemas for selected tools |
| Natural-language search over previously stored tool responses (Qdrant-backed) |
| Retrieve a full stored response by point ID from search results |
| Summarize recent tool usage patterns and activity |
| Run a sandboxed Python block that chains real tool calls via |
Why it matters:
💰 Massive token savings — 7 schemas instead of 90+, with full schemas fetched only for the tools actually used
🔗 One round-trip instead of many — search → filter → act happens inside a single
executeblock, not a chain of client round-trips🧰 Batteries-included sandbox — 40+ built-in helpers (
now(),days_ago(),to_json(),re_find(),gather_tools(), …) cover dates, JSON, URLs, regex, math, and batch calls without any imports
# One execute block: find a Drive file, then email its link
files = await call_tool("search_drive_files", {"query": "Q4 report"})
link = files["files"][0]["webViewLink"]
result = await call_tool("send_gmail_message", {
"to": "manager@company.com",
"subject": "Q4 Report",
"body": "Here's the Q4 report: " + link,
})
return resultPrefer the classic catalog? Opt out and every tool is exposed directly to the client:
ENABLE_CODE_MODE=false # expose the full 90+ tool catalog insteadCode Mode and the classic catalog are mutually exclusive — when Code Mode is active, direct tool calls are replaced by the search +
executepattern. Discovery tools always see the full catalog, regardless of session-level filtering.
🎯 Service Capabilities
GoogleUnlimited supports 10 Google Workspace services with 90+ specialized tools:
Service | Icon | Tools | Key Features | Documentation |
Gmail | 📧 | 14 | Send, reply, labels, filters, search, allowlist, interactive draft preview card | |
Drive | 📁 | 9 | Upload, download, sharing, Office docs, file management | |
Docs | 📄 | 4 | Create, edit, format, batch operations | |
Sheets | 📊 | 7 | Read, write, formulas, formatting | |
Slides | 🎯 | 5 | Presentations, templates, export | |
Calendar | 📅 | 9 | Events, scheduling, attendees, timezones | |
Forms | 📝 | 8 | Creation, responses, validation, publishing | |
Chat | 💬 | 24 | Messaging, cards, spaces, webhooks, unified cards | |
Photos | 📷 | 12 | Albums, upload, search, metadata, smart search | |
People | 👤 | 4 | Name→email search (contacts + org directory), contact labels |
📚 API Documentation Resources:
🔗 Complete API Reference - Comprehensive documentation for all 92+ tools across 10 services
📧 Gmail API Guide - Email management, labels, filters, and search operations
📁 Drive API Guide - File operations, sharing, and Office document handling
📊 Sheets API Guide - Spreadsheet data manipulation and formatting
📅 Calendar API Guide - Event scheduling and timezone management
🧠 Middleware Architecture
GoogleUnlimited uses a middleware architecture that provides seamless service integration, intelligent resource management, and powerful templating capabilities.

🔧 Core Middleware Components
🏷️ TagBasedResourceMiddleware: Intelligent resource discovery using URI patterns (
service://gmail/messages,user://current/email)🧠 QdrantUnifiedMiddleware: AI-powered semantic search across all tool responses with vector embeddings
🎨 TemplateMiddleware: Advanced Jinja2 template system for beautiful, structured output formatting
✨ Architecture Benefits
🔄 Unified Resource Access: URI-based access to service data without API calls
🧠 Semantic Intelligence: Natural language search across all stored responses
🎨 Visual Excellence: Consistent, beautiful output formatting for optimal AI consumption
💰 Token Efficiency: Template macros reduce token usage by 60-80% through structured data rendering
⚡ Performance: 30x faster than traditional approaches through intelligent caching
📚 Middleware Documentation Resources:
📖 Middleware Architecture Guide - Complete middleware system documentation and implementation details
🏷️ TagBasedResourceMiddleware - URI pattern resource discovery and management
🧠 QdrantUnifiedMiddleware - AI-powered semantic search and vector embeddings
🎨 TemplateMiddleware - Advanced Jinja2 template system for output formatting
🔧 SessionToolFilteringMiddleware - Per-session tool enable/disable management
🚀 Minimal Tools Startup
By default, GoogleUnlimited starts with only 5 protected tools enabled for optimal performance and security. This allows clients to enable only the tools they need.
Protected Tools (Always Available):
manage_tools- Enable/disable tools globally or per-sessionmanage_tools_by_analytics- Analytics-based tool managementhealth_check- Server health and configuration statusstart_google_auth- Initiate OAuth authenticationcheck_drive_auth- Verify authentication status
Configuration:
# Default: Start with minimal tools (only 5 protected tools)
MINIMAL_TOOLS_STARTUP=true
# Optional: Pre-enable specific services at startup
MINIMAL_STARTUP_SERVICES=drive,gmail,calendar
# Disable minimal startup (enable all 92+ tools immediately)
MINIMAL_TOOLS_STARTUP=falseEnabling Tools at Runtime:
# Enable all tools globally
manage_tools(action="enable_all")
# Enable specific tools
manage_tools(action="enable", tool_names=["search_drive_files", "list_gmail_labels"])
# List all registered tools (shows enabled/disabled status)
manage_tools(action="list")🔧 Session-Scoped Tool Management
GoogleUnlimited supports per-session tool enable/disable functionality, allowing different MCP clients to have different tool availability without affecting other connected clients.
Key Features:
Session Isolation: Disable tools for one client session without affecting others
Non-Invasive: Session-scoped operations never modify the global tool registry
Protected Tools: Core management tools (
manage_tools,health_check, etc.) always remain availableMiddleware-Based: Uses
SessionToolFilteringMiddlewarefor protocol-level filtering
Usage Examples:
# Disable tools for this session only (other clients unaffected)
manage_tools(action="disable", tool_names=["send_gmail_message"], scope="session")
# Disable all except specific tools for this session
manage_tools(action="disable_all_except", tool_names=["search_drive_files", "list_events"], scope="session")
# Re-enable all tools for this session
manage_tools(action="enable_all", scope="session")
# Global operations (original behavior, affects all clients)
manage_tools(action="disable", tool_names=["send_gmail_message"], scope="global")Response Structure:
{
"success": true,
"action": "disable_all_except",
"scope": "session",
"enabledCount": 94,
"disabledCount": 0,
"toolsAffected": ["tool1", "tool2", "..."],
"sessionState": {
"sessionId": "f725be09...",
"sessionAvailable": true,
"sessionDisabledTools": ["tool1", "tool2"],
"sessionDisabledCount": 89
},
"message": "Kept 5 tools, disabled 89 tools for this session"
}📚 Skills Provider
When enabled via ENABLE_SKILLS_PROVIDER=true, GoogleUnlimited generates skill documents from ModuleWrapper instances and serves them via FastMCP's SkillsDirectoryProvider. Skills provide structured knowledge that LLMs can reference for complex multi-step tasks.
Currently supported modules:
card_framework→gchat-cardsskill (Google Chat card DSL reference, component hierarchy, examples)
Configuration:
ENABLE_SKILLS_PROVIDER=true # Enable skill generation
SKILLS_DIRECTORY=~/.claude/skills # Output directory (default)Skills are auto-regenerated on each startup and immediately available via the FastMCP skills system.
🖥️ Tool Management Dashboard
GoogleUnlimited includes a built-in Tool Management Dashboard served via the MCP Apps ui:// resource scheme. This provides a visual interface for monitoring and managing tool availability across sessions.

Features:
Service-grouped tool view — tools organized by Google service (Gmail, Drive, Sheets, etc.) with counts
Session state visibility — see which tools are enabled, disabled, or session-disabled at a glance
Filter chips — quickly filter by service to focus on relevant tools
Live data — powered by
DashboardCacheMiddlewarewhich caches list-tool results for instantui://data-dashboardresource access
The dashboard is automatically wired to all list tools via wire_dashboard_to_list_tools() — no per-tool configuration needed.
📊 Data Dashboards & Result Cards
Under Code Mode, a list tool called inside execute draws a data dashboard
card: a searchable, sortable, paginated table. Gmail label colours render as
the chips Gmail itself draws; nested values (filter criteria, actions) flatten
to readable text.

The rows never enter the model's context. Hosts hand a tool result's
structuredContent to the model as well as to the renderer, so a table
embedded in the card cost ~80 tokens a row on every call — about 5k tokens for
65 labels. The card now ships as an empty shell (~375 tokens whatever the row
count) and fetches its rows itself once drawn, through a UI-only
dashboard_rows app tool keyed by an unguessable per-result token. The text
content the model reads is unchanged.
Every execute block also ends in a result card showing the block's own
return value — JSON printed one key per line, with a Copy button.

📧 Gmail Draft Preview Card
preview_gmail_draft returns a second MCP App: an interactive card showing a
Gmail draft exactly as it will arrive, with Send, Save and Discard
buttons and editable To/Cc/Bcc fields backed by contact autocomplete.

# Draft and preview in one step — or pass a draft_id from draft_gmail_message
preview_gmail_draft(subject="Q3 numbers", body="...", to="team@example.com")The card renders the real MJML/HTML body in a sandboxed iframe (no scripts —
Gmail strips those too, so a script-free preview is both safer and more
honest). Remote images are fetched and inlined as data: URIs, because hosts
build the iframe's img-src from declared CSP domains and scheme-only grants
are not honoured everywhere.
Payload discipline. A rendered view is not free: it travels in the tool
result's structuredContent, and some hosts surface that to the model as well
as to the renderer. Inlined images are therefore capped (150 KB per image,
500 KB per preview), and the server only builds the card for clients that show
some sign of being able to draw it — either they advertised the MCP Apps UI
extension, or their clientInfo.name matches DRAFT_PREVIEW_UI_CLIENTS.
Everything else gets a compact text summary, skipping the image fetch and
contact lookup entirely.
The server logs each client's identity once per session, so you can see which way a given host was routed:
[ui-gating] client=claude-ai version=2.1.0 advertises_extension=False allowlisted=True -> card📚 Full details, including the Code Mode interaction and per-flag behaviour: docs/GMAIL_DRAFT_APP.md
🔗 URL-Based Service Filtering (HTTP Transport)
When using HTTP/SSE transport, you can filter tools by service directly via URL query parameters - no code required:
# Enable only Gmail tools
http://localhost:8002/mcp?service=gmail
# Enable Gmail + Drive + Calendar
http://localhost:8002/mcp?service=gmail,drive,calendar
# Resume a previous session
http://localhost:8002/mcp?uuid=your-session-id
# Resume session with specific services
http://localhost:8002/mcp?uuid=abc123&service=gmail,drive
# Disable minimal startup (enable all tools)
http://localhost:8002/mcp?minimal=falseAvailable URL Parameters:
Parameter | Example | Description |
|
| Comma-separated list of services to enable |
|
| Resume a previous session by ID |
|
| Override minimal startup mode |
Available Services: gmail, drive, calendar, docs, sheets, slides, photos, chat, forms, people
📚 Session Tool Management Resources:
🔧 SessionToolFilteringMiddleware Guide - Complete documentation for per-session tool management
🎨 Template System
GoogleUnlimited features powerful Jinja2 template macros that transform raw Google Workspace data into visually stunning, AI-optimized formats.
🎯 Available Template Macros
Template File | Macro | Purpose | Key Features |
|
| Gmail label visualization | Interactive chips, unread counts, direct Gmail links |
|
| Calendar & events dashboard | Primary/shared calendars, upcoming events, dark theme |
|
| Calendar events dashboard | Event cards, time/location details, clickable links, dark theme |
|
| Professional reports | Metrics, tables, charts, company branding |
|
| Rich HTML emails | Multiple signatures, gradients, responsive design |
💡 Template Macro Examples
Gmail Labels Visualization - Transform label lists into beautiful interactive chips:
{{ render_gmail_labels_chips( service://gmail/labels , 'Label summary for: ' + user://current/email ) }}Calendar Dashboard - Create comprehensive calendar overviews:
{{ render_calendar_dashboard( service://calendar/calendars, service://calendar/events, 'My Calendar Overview' ) }}Calendar Events Dashboard - Transform calendar events into beautiful, interactive event cards:
{{ render_calendar_events_dashboard( service://calendar/events , 'Upcoming Events for: ' + user://current/email.email ) }}
This macro creates a stunning dark-themed dashboard featuring:
📅 Interactive Event Cards: Each event is rendered as a clickable card that opens in Google Calendar
🕐 Smart Time Display: Automatically formats all-day events vs. timed events with timezone support
📍 Location Integration: Displays meeting locations and virtual meeting links
👥 Attendee Information: Shows attendee counts and participant details
✅ Status Indicators: Color-coded status (confirmed, tentative, cancelled) with visual feedback
📱 Responsive Design: Mobile-optimized layout with touch-friendly interactions
🎨 Dark Theme Styling: Professional appearance with gradient backgrounds and hover effects
Professional Documents - Generate reports with metrics and charts:
{{ generate_report_doc(
report_title='Q4 Performance Report',
metrics=[{'value': '$1.2M', 'label': 'Revenue', 'change': 15}],
company_name='Your Company'
) }}🔍 Macro Discovery & Dynamic Creation
Explore all available macros using the template resource system:
# Access the template://macros resource to discover all available macros
macros = await access_resource("template://macros")
# Returns comprehensive macro information with usage examples
# Access specific macro details
macro_details = await access_resource("template://macros/render_gmail_labels_chips")🎯 Dynamic Macro Creation
Create custom macros at runtime using the create_template_macro tool:
# Create a new macro dynamically
await create_template_macro(
macro_name="render_task_status_badge",
macro_content='''
{% macro render_task_status_badge(status, size='small') %}
{% if status == 'completed' %}
<span class="status-badge status-completed {{ size }}">✅ Complete</span>
{% elif status == 'in_progress' %}
<span class="status-badge status-in-progress {{ size }}">🔄 In Progress</span>
{% else %}
<span class="status-badge status-pending {{ size }}">⏳ {{ status|title }}</span>
{% endif %}
{% endmacro %}
''',
description="Renders visual status badges for task states with appropriate icons",
usage_example="{{ render_task_status_badge('completed', 'large') }}",
persist_to_file=True
)
# Immediately use the newly created macro
await send_gmail_message(
html_body="Task Status: {{ render_task_status_badge('completed', 'large') }}"
)DSL-powered macros — dynamic macros can also embed Google Chat card DSL notation to generate rich, structured cards. The DSL symbols define the card layout while Jinja2 handles dynamic content:
{# workspace_dashboard.j2 — a dynamic macro that outputs a Google Chat card #}
{% macro workspace_dashboard(user_email, stats=None, quick_actions=None) %}
{% set username = user_email.split('@')[0] if user_email else 'User' %}
{% set default_stats = stats or [
{'label': 'Emails', 'value': '12 unread'},
{'label': 'Calendar', 'value': '3 meetings today'},
{'label': 'Tasks', 'value': '5 pending'}
] %}
§[δ×3, ℊ[ǵ×4], §[δ×2, Ƀ[ᵬ×3]]]
Welcome back, {{ username | title }}!
Your Workspace Overview:
{% for stat in default_stats %}
- {{ stat.label }}: {{ stat.value }}
{% endfor %}
Actions:
- Button: Open Gmail → https://mail.google.com
- Button: Open Calendar → https://calendar.google.com
- Button: Open Drive → https://drive.google.com
{% endmacro %}The DSL line §[δ×3, ℊ[ǵ×4], §[δ×2, Ƀ[ᵬ×3]]] defines the card structure: a Section with 3 DecoratedText widgets, a Grid with 4 items, and a nested Section with 2 DecoratedText widgets and a ButtonList with 3 buttons. The Jinja2 template fills in the content dynamically — and because it's persisted to templates/dynamic/, it's immediately available to send_dynamic_card and other tools.
Key Features:
⚡ Immediate Availability: Macros are instantly available after creation
🎯 Resource Integration: Automatically available via
template://macros/macro_name💾 Optional Persistence: Save macros to disk for permanent availability
🔄 Template Processing: Full Jinja2 syntax validation and error handling
💬 DSL Integration: Macros can output card DSL notation for rich Google Chat cards
🚀 Real-World Usage
Templates can be directly used in tool calls for beautiful, structured output:
# Send a beautiful email with calendar dashboard
await send_gmail_message(
to="manager@company.com",
subject="Weekly Schedule Update",
html_body="{{ render_calendar_events_dashboard( service://calendar/events, 'My upcoming events') }}",
content_type="mixed"
)
# Generate and send a professional report
await create_doc(
title="Q4 Performance Report",
content="{{ generate_report_doc( report_title='Quarterly Results', company_name='GoogleUnlimited' ) }}"
)📚 Template System Resources:
🎨 Template Directory - Complete collection of Jinja2 templates and macros
💌 Beautiful Email Templates - Rich HTML email styling and themes
🏷️ Gmail Label Cards - Interactive label visualization with chips
📅 Calendar Dashboard - Event timeline and scheduling views
📄 Document Templates - Structured document formatting
🗂️ Resource Discovery
GoogleUnlimited provides a powerful MCP resource system that enables lightning-fast data access without API calls through intelligent URI patterns.

🎯 Resource URI Patterns
Pattern | Purpose | Example | Returns |
| User authentication status |
| Profile + auth state |
| Available service lists |
| [filters, labels] |
| All items in list |
| All Gmail labels |
| Specific item details |
| INBOX label details |
| Recent items |
| Recent Drive files |
| Semantic search |
| Relevant responses |
🏗️ Key Resource Files
resources/user_resources.py: Authentication, profiles, session management (1,812 lines)resources/service_list_resources.py: Service discovery through TagBasedResourceMiddleware (446 lines)middleware/qdrant_core/resources.py: AI-powered search and analytics (319 lines)
⚡ Lightning-Fast Access
# Instant Gmail labels (no API call needed)
labels = await access_resource("service://gmail/labels")
# Current user info from session
user = await access_resource("user://current/email")
# Semantic search across all tool responses
results = await access_resource("qdrant://search/gmail errors today")
# Recent calendar events
events = await access_resource("recent://calendar")📚 Resource System Documentation:
🗂️ User Resources - Authentication, profiles, and session management (1,812 lines)
🏷️ Service List Resources - Service discovery through TagBasedResourceMiddleware (446 lines)
🧠 Qdrant Core Resources - AI-powered search and analytics (319 lines)
📋 Resource Patterns Guide - Complete URI pattern reference and usage examples
🧪 Testing Framework
GoogleUnlimited includes comprehensive testing with client tests that validate MCP usage exactly as an LLM would experience it, plus additional testing suites. 559 tests passing with 100% pass rate.
🎯 Client Testing Focus

The client tests are the most important component - they provide deterministic testing of MCP operations using real resource integration and standardized patterns across all 92+ tools and 9 Google services. These tests validate both explicit email authentication and middleware injection patterns.
🚀 Quick Test Commands
# 🧪 Run all client tests (primary test suite)
uv run pytest tests/client/ -v
# 📧 Test specific service
uv run pytest tests/client/ -k "gmail" -v
# 🔐 Authentication required tests
uv run pytest tests/client/ -m "auth_required" -v🔬 Real Resource ID Integration
The testing framework fetches real IDs from service resources for realistic testing:
# Available fixtures for real resource testing
real_gmail_message_id # From service://gmail/messages
real_drive_document_id # From service://drive/items
real_calendar_event_id # From service://calendar/events
real_photos_album_id # From service://photos/albums
real_forms_form_id # From service://forms/forms
real_chat_space_id # From service://chat/spaces🔄 CI/CD Pipeline
Automated testing and publishing via GitHub Actions:
CI Workflow: Runs on every PR and push to main
Python 3.11 & 3.12 matrix testing
Linting with
ruff checkand formatting withruff formatFull test suite execution
TestPyPI Publishing: Automated package publishing for testing
📚 Testing Resources:
📋 Client Testing Framework Guide - Complete client testing documentation and patterns
🧪 Client Tests Directory - Real resource integration tests for deterministic MCP validation
🤖 MCP Client Integration - Learn more about MCP client patterns and usage
🔐 Authentication Patterns - Email vs middleware injection validation testing
🔒 Security & Authentication
GoogleUnlimited implements enterprise-grade security with OAuth 2.1 + PKCE, advanced session management, and comprehensive audit capabilities.

🛡️ Authentication Flows
🌐 MCP Inspector OAuth: MCP Spec compliant with Dynamic Client Registration
🖥️ Direct Server OAuth: Web-based authentication for direct access
🔧 Development JWT: Testing mode with generated tokens
📁 Enhanced File Credentials: Persistent storage with encryption options
🔑 Custom OAuth Clients: Bring your own OAuth credentials with automatic fallback
🪪 Per-User API Keys: Individual keys generated on OAuth completion with credential isolation
✨ Security Features
🔐 OAuth 2.1 + PKCE: Modern authentication with proof-of-key exchange (supports public clients)
🔑 Per-User API Keys: Unique, revocable keys per user with hash-only storage and timing-safe lookup
🛡️ Credential Isolation: Auth provenance-based access control prevents cross-user credential inheritance
🔗 Account Linking: Bidirectional account linking for multi-account per-user key access
🔒 Crypto-Bound Encryption: HKDF-SHA256 derived encryption keys bound to
MCP_API_KEY🔒 Session Isolation: Multi-tenant support preventing data leaks
🏷️ 27+ API Scopes: Granular permission management across all services
📊 Audit Logging: Complete security event tracking with auth provenance
🔐 AES-256 Encryption: Credential storage with legacy key migration support
🔄 Three-Tier Fallback: Robust credential persistence across server restarts (State Map → UnifiedSession → Context Storage)
🧹 Sensitive Data Stripping: Auth metadata removed from Qdrant embeddings before storage
⚙️ Security Configuration
# 🔒 Security settings in .env
CREDENTIAL_STORAGE_MODE=FILE_ENCRYPTED
SESSION_SECRET_KEY=your-secret-key
SESSION_TIMEOUT_MINUTES=30
ENABLE_AUDIT_LOGGING=true
GMAIL_ALLOW_LIST=trusted@example.com📚 Security Documentation Resources:
🛡️ Unified OAuth Architecture - Complete security architecture and authentication design
🔐 OAuth 2.1 + PKCE Implementation - Modern authentication with proof-of-key exchange
🏠 Session Management Guide - Multi-tenant support and session isolation
🔒 Encryption & Storage - AES-256 credential encryption and machine-specific keys
📊 Audit Logging System - Complete security event tracking and monitoring
🚀 Ready to revolutionize your Google Workspace integration?
📚 Documentation • 🔧 Configuration • 🎯 API Reference • 🧪 Testing
Available Tools
7 toolsexecuteExecuteA
Run sandboxed Python that calls this server's Google Workspace tools via await call_tool(tool_name, params), chaining calls in one block.
Use when: you know which tools to call. To find tool names first use search or tags; for exact parameters use get_schema; to look up past results instead, use semantic_search.
Behavior: each call_tool runs the real tool immediately — sends, edits, and deletes take effect; there is no dry-run.
Use return to produce output; prefer returning the final answer from a single block.
Only call_tool(tool_name: str, params: dict) -> Any is available in scope. Unknown tool names raise NotFoundError; disallowed syntax raises SandboxError.
SANDBOX RESTRICTIONS — these produce SandboxError, avoid them:
sorted_(items, key=lambda x: x['k'])→ lambda args fail; use builtins likekey=lenor sort manuallyimportonly covers a small stdlib subset (e.g. json); no third-party modules — prefer the built-in helpers listed below
Built-in helpers (import is not available — use these instead):
now(tz_offset=0)→ current datetime string (UTC by default)today(tz_offset=0)→ current date 'YYYY-MM-DD' (UTC by default)days_ago(n, tz_offset=0)→ ISO datetime string N days agohours_ago(n, tz_offset=0)→ ISO datetime string N hours agoformat_date(iso_str, fmt='%Y-%m-%d %H:%M')→ formatted dateparse_date(iso_str)→ normalized ISO datetimetimestamp()→ current unix timestamp (int)to_json(obj, indent=None)→ JSON stringfrom_json(s)→ parsed objecturl_encode(s)→ URL-encoded stringurl_decode(s)→ URL-decoded stringurl_join(base, *parts)→ joined URL pathquery_string(params)→ URL query string from dictre_find(pattern, text)→ list of matchesre_match(pattern, text)→ boolre_sub(pattern, repl, text)→ substituted stringtruncate(text, n=80)→ truncated with '...'dedent(text)→ remove common leading whitespacewrap_text(text, width=72)→ word-wrap to widthpad_left(s, width, char=' ')→ right-justify / zero-padpad_right(s, width, char=' ')→ left-justifyjoin(items, sep=', ')→ joined stringhtml_escape(s)→ HTML-safe stringsqrt(n),ceil(n),floor(n)→ mathround_(n, digits=2),abs_(),min_(),max_(),sum_()→ mathsorted_(items, key=None, reverse=False)→ sorted listunique(items)→ deduplicated list (preserves order)flatten(lists)→ flat list from nested listscounter(items)→ dict of {item: count}chunk(items, size)→ list of chunkszip_(*iterables)→ zipped as list of listsdict_get(d, 'a.b.c', default=None)→ nested dict accessmd5(s),sha256(s)→ hash hex digestsgather_tools(calls)→ run multiple tool calls sequentially;callsis a list of[tool_name, params]pairs, returns list of results (assign to variable, then index:r = await gather_tools([...]); a, b = r[0], r[1])sleep(seconds)→ async sleep
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Python async code to execute tool calls via call_tool(name, arguments) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
There are no annotations, so the description carries the full burden, and it does so thoroughly. It discloses that each call_tool runs the real tool immediately with sends/edits/deletes taking effect and no dry-run, plus sandbox restrictions, error types, and disallowed syntax. This is substantial behavioral context beyond what the schema provides.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured with clear sections: use-when, behavior, sandbox restrictions, and built-in helpers. Core usage and side effects are front-loaded, and every block provides actionable information rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that annotations and an output schema are absent, the description is remarkably complete. It covers selection criteria, invocation syntax, execution environment, side effects, error modes, restrictions, and helper APIs, so an agent can use this tool without needing additional documentation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already describes the single `code` parameter at 100% coverage, but the description adds far more semantic value: valid async syntax, `call_tool` signature, use of `return`, restrictions on `import`, sandbox errors, and a full list of available built-in helpers. This gives the agent everything needed to construct valid code.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a precise verb and resource: running sandboxed Python that calls this server's Google Workspace tools via `await call_tool(tool_name, params)` and chaining calls in one block. It also distinguishes itself clearly from discovery/search siblings by framing this as the execution step once tool names are known.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit 'Use when' condition: when you know which tools to call. It also names alternatives for other cases: `search` or `tags` for finding tool names, `get_schema` for exact parameters, and `semantic_search` for past results, providing clear routing to sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fetch_documentFetch DocumentA
Preview one stored tool response by its Qdrant point ID.
Use when: inspecting a hit returned by semantic_search. To find
point IDs in the first place, use semantic_search; for the full
untruncated content, call the fetch tool inside an execute block.
Behavior: read-only. Returns: tool name, service, timestamp, user, argument count, and the first 500 characters of stored content. Errors: 'Document not found' for unknown or expired point IDs.
| Name | Required | Description | Default |
|---|---|---|---|
| point_id | Yes | Qdrant point ID (UUID) from a search result | |
| user_google_email | No | User's Google email (auto-injected by middleware) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully carries the behavioral disclosure burden. It states 'Behavior: read-only', describes the exact return fields including the 500-character truncation, and documents the error condition 'Document not found' for unknown or expired IDs. This is unusually transparent for a tool description.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, well-organized with labeled sections, and front-loads the core purpose. Every sentence adds useful content, and there is no redundant repetition of schema or annotation details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no output schema, the description enumerates the return fields and truncation behavior, making the tool's output predictable. It also covers errors, read-only behavior, and usage context, making the description complete for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both parameters clearly. The description adds context around the point_id's role in previewing a stored response, but does not need to add more because the parameter semantics are fully captured in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Preview one stored tool response') and identifies the resource by 'Qdrant point ID', clearly distinguishing this from sibling search and execute tools. It also explicitly indicates what it is not for, such as full untruncated content, which further sharpens purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'Use when' section directly instructs to use this tool when inspecting a hit from semantic_search, and explicitly points to alternatives for finding point IDs and retrieving full content. This is exemplary routing guidance that leaves no ambiguity about when to use this tool versus siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_schemaGet SchemaA
Get parameter schemas for named tools before calling them via execute. Use when: you already have tool names (from search or tags) and need exact parameters. Not for discovery — use search for that. Returns: per-tool parameter markdown ('detailed', default), names + descriptions ('brief'), or full JSON schemas ('full'); unknown names are reported under 'Tools not found'.
| Name | Required | Description | Default |
|---|---|---|---|
| tools | Yes | List of tool names to get schemas for | |
| detail | No | 'brief' for names and descriptions, 'detailed' for parameter schemas as markdown, 'full' for complete JSON schemas | detailed |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It discloses the output formats for each detail mode and the unknown-name handling behavior ('reported under Tools not found'). It does not explicitly state side effects, but the read-only nature is strongly implied by the verb 'get' and the schema-fetching purpose.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact, front-loaded with the core purpose, and uses clear logical sections ('Use when', 'Not for discovery', 'Returns'). Every sentence earns its place without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is complete for a tool with no output schema and no annotations. It covers the main purpose, usage conditions, output formats, defaults, and error handling for unknown tool names. No critical operational gap remains for an agent deciding how to call this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Input schema coverage is 100%, so the baseline is 3. The description mostly restates what the schema already says about 'detail' and 'tools'; it adds minor value with 'per-tool parameter markdown' and unknown-name behavior, but does not substantially deepen parameter understanding beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Get parameter schemas for named tools before calling them via execute.' It clearly differentiates from the sibling search tool by framing this as a pre-execute lookup step, not a discovery mechanism.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use the tool ('when you already have tool names... and need exact parameters'), when not to use it ('Not for discovery'), and names the alternative ('use search for that'). This gives an agent unambiguous routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
searchSearchA
Find this server's Google Workspace tools by keyword (BM25 over names, descriptions, and tags). Use when: you don't know the exact tool name yet. To browse by category use tags; once you have names, use get_schema for parameters, then execute to call them. To search past results rather than tools, use semantic_search. Returns: matching tools as names + descriptions ('brief', default), parameter markdown ('detailed'), or complete JSON definitions ('full'). An empty result means no keyword match — retry with different terms.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Filter to tools with any of these tags before searching | |
| limit | No | Maximum number of results to return | |
| query | Yes | Search query to find available tools | |
| detail | No | 'brief' for names and descriptions, 'detailed' for parameter schemas as markdown, 'full' for complete JSON schemas | brief |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It does this well by revealing the BM25 ranking mechanism, the three return detail modes, the default 'brief' mode, and the meaning of an empty result ('no keyword match — retry with different terms'). This gives an agent a clear behavioral model beyond what the schema states.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and well-structured. The primary purpose is stated first, followed by explicit usage guidance, sibling routing, and return behavior. Every sentence earns its place; there is no filler or repetition of schema details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a search tool with no annotations and no output schema, the description is thorough: it explains what is searched, when to use it, how to route to alternatives, what the return values look like in each detail mode, and how to interpret empty results. Nothing critical is missing for safe and correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all parameters clearly. The description adds a little context around the detail parameter's output modes, but most of what it says about parameters mirrors the schema. This meets the baseline but does not go substantially beyond it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear verb and resource: 'Find this server's Google Workspace tools by keyword,' and specifies the search mechanism (BM25 over names, descriptions, and tags). It also distinguishes the tool from siblings like tags and semantic_search, so an agent can immediately tell what this tool is for.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use guidance: 'Use when: you don't know the exact tool name yet.' It also names alternatives and the conditions for choosing them, such as using tags to browse by category, get_schema for parameters, execute to call, and semantic_search for past results. This is exemplary routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
semantic_searchSemantic SearchA
Search the Qdrant vector store of this server's past tool responses and card templates.
Use when: looking up previous results, usage history, or analytics ('service:gmail last week', 'tool:search recent', 'overview'). For discovering tools to call, use search; to preview one stored document, pass its point ID to fetch_document.
Modes: semantic text similarity; service/tool history queries; analytics ('overview', 'usage stats'); filter_dsl for structured filters; positive/negative point IDs for recommendation; query_dsl for fusion/discover/order-by; prefetch_dsl for multi-stage retrieval.
Behavior: read-only against the local Qdrant instance; no Google APIs are called. Returns: scored rows 'score service/tool timestamp id:'. Errors: 'Search failed' when Qdrant is unreachable; 'No results' when nothing clears score_threshold (default 0.3 — lower it to widen the net).
DSL filter symbols: D_5=DatetimeRange, ʄ=FieldCondition, ƒ=Filter, F_6=FilterSelector, ℏ=HasIdCondition, I_2=IsEmptyCondition, I_0=IsNullCondition, ɱ=MatchAny, ṁ=MatchText, M_0=MatchTextAny, ☆=MatchValue, ř=Range Query-DSL symbols: Å=AcornSearchParams, C_14=ContextExamplePair, ¢=ContextPair, C_0=ContextQuery, D_6=DiscoverInput, D_2=DiscoverQuery, D_4=DiscoverRequest, D_21=DiscoverRequestBatch, ℱ=Fusion, φ=FusionQuery, ø=OrderBy, ɵ=OrderByQuery, ¶=Prefetch, ʔ=QuantizationSearchParams, R_12=RecommendGroupsRequest, R_2=RecommendInput, R_4=RecommendQuery, R_5=RecommendRequest, R_18=RecommendRequestBatch, R_10=RecommendStrategy, ♦=SearchParams Example: ƒ{must=[ʄ{key="tool_name", match=☆{value="send_dynamic_card"}}]} MatchAny: ƒ{must=[ʄ{key="tool_name", match=ɱ{any=["tool_a", "tool_b"]}}]}
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum results to return | |
| query | Yes | Search query — natural language, 'service:gmail recent', 'overview', 'id:<point_id>', or semantic text when filter_dsl is set | |
| dry_run | No | If true with filter_dsl, parse and validate DSL without executing the query | |
| query_dsl | No | Query DSL for recommend, discover, fusion, or order-by queries | |
| collection | No | Qdrant collection to search. Default: mcp_tool_responses | |
| filter_dsl | No | Qdrant DSL filter notation for precise filtering (see docstring for symbols) | |
| prefetch_dsl | No | Multi-stage prefetch DSL for hierarchical search strategies | |
| score_threshold | No | Minimum similarity score (0.0-1.0) | |
| user_google_email | No | User's Google email (auto-injected by middleware) | |
| negative_point_ids | No | Point IDs to use as negative examples for recommendation search | |
| positive_point_ids | No | Point IDs to use as positive examples for recommendation search |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It explicitly states the tool is read-only, that no Google APIs are called, the exact return row format, the two error messages ('Search failed', 'No results'), and the effect of score_threshold. This is far more transparent than typical tool descriptions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured and front-loaded: purpose, use-when, modes, behavior, returns, errors, then reference material. It is long, but the DSL symbol tables and examples earn their place because the schema refers to 'see docstring for symbols.' A minor redundancy between the 'Modes' section and the query parameter description prevents a perfect score.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex 11-parameter tool with no output schema and no annotations, this description is remarkably complete: it covers return shape, error behavior, default threshold semantics, DSL syntax, example queries, sibling routing, and parameter mode mappings. An agent has nearly everything needed to invoke it correctly and interpret the response.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, giving a baseline of 3, but the description adds substantial meaning beyond the schema: a DSL symbol legend, a worked filter_dsl example, a MatchAny example, mapping of query_dsl/filter_dsl/prefetch_dsl to modes, explanation of positive/negative point IDs, and guidance to lower score_threshold. This meaningfully helps an agent construct parameters correctly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description opens with a specific verb and resource: 'Search the Qdrant vector store of this server's past tool responses and card templates.' It also names sibling tools and clarifies what they do instead, so an agent can distinguish semantic_search from search and fetch_document without ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'Use when' section explicitly lists trigger conditions: looking up previous results, usage history, or analytics, with concrete query examples. It also provides exclusion guidance: 'For discovering tools to call, use search; to preview one stored document, pass its point ID to fetch_document.' This is exactly the when/when-not context an agent needs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tagsTagsA
List this server's tool tags (service areas like gmail, drive, docs, photos) with tool counts. Use when: browsing what capability areas exist before a targeted lookup. For keyword lookup use search; for parameters of known tools use get_schema. Returns: '- tag (N tools)' lines at detail='brief' (default), or every tool listed under each tag at detail='full'.
| Name | Required | Description | Default |
|---|---|---|---|
| detail | No | Level of detail: 'brief' for tag names and counts, 'full' for tools listed under each tag | brief |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden, and it does well: it specifies the exact output shape at default detail ('- tag (N tools)' lines) and the change at detail='full'. It clearly frames the operation as a non-mutating listing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three compact sentences front-load the core action and use case before return details. There is no filler or unnecessary repetition of schema content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple list tool with one optional schema-defined parameter and no output schema, the description covers purpose, routing, default behavior, and return format. Nothing material needed to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already fully documents the single parameter with its enum, default, and per-value meaning, so the baseline is 3. The description adds the concrete output format for brief detail and confirms what full detail returns, which is a small but meaningful addition.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise action ('List this server's tool tags...') with resource and scope, plus concrete examples of categories like gmail, drive, docs, and photos. The mention of tool counts and the overview nature distinguishes it from sibling tools such as search and get_schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states the intended use case ('browsing what capability areas exist before a targeted lookup') and names alternatives for adjacent cases: 'For keyword lookup use search; for parameters of known tools use get_schema.' This gives an agent clear routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tool_activityTool ActivityA
Show usage analytics for this server's tools: call counts, error rates, last-used times.
Use when: answering 'what has been used or failing lately'. To read an individual response, pass a sample point ID to fetch_document; to discover tools to call, use search instead.
Behavior: read-only aggregation over the Qdrant response store. Returns: a text dashboard grouped by tool_name or user_email, with sample point IDs per group. Errors: 'Analytics failed' when the response store is unreachable.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum groups to show | |
| group_by | No | Group results by 'tool_name' or 'user_email' | tool_name |
| user_google_email | No | User's Google email (auto-injected by middleware) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses read-only behavior ('read-only aggregation over the Qdrant response store'), return format ('text dashboard... with sample point IDs per group'), and an error condition ('Analytics failed' when the response store is unreachable). It does not mention authentication or rate limits, but for this tool the provided behavioral details are substantive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well structured with labeled segments ('Use when', 'Behavior', 'Returns', 'Errors'), front-loads the core purpose, and every sentence adds distinct value. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no output schema and no annotations, the description provides enough context for correct invocation: what it returns (text dashboard), how it groups, what error to expect, and when to use alternatives. All three optional parameters are already covered by the schema, so nothing needed for this tool is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter is already documented in the schema. The description mentions grouping by tool_name or user_email, which mirrors the group_by schema description, but does not add new semantic detail beyond that. Baseline 3 is appropriate when the schema handles parameter documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Show usage analytics for this server's tools: call counts, error rates, last-used times'), and later explicitly contrasts with fetch_document and search, distinguishing its purpose. An agent can immediately tell what this tool does and how it differs from siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Contains explicit 'Use when' guidance ('answering what has been used or failing lately'), plus clear redirections: 'pass a sample point ID to fetch_document' and 'use search instead'. This leaves no ambiguity about when to select this tool over alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
6 tool updates
v3.0.0- Changed
fetch_document1 field changed- changed
Output schema / (root)Previous value: -{ - "properties": { - "result": { - "type": "string" - } - }, - "required": [ - "result" - ], - "type": "object", - "x-fastmcp-wrap-result": true -}New value: +null
- Changed
get_schema1 field changed- changed
Output schema / (root)Previous value: -{ - "properties": { - "result": { - "type": "string" - } - }, - "required": [ - "result" - ], - "type": "object", - "x-fastmcp-wrap-result": true -}New value: +null
- Changed
search1 field changed- changed
Output schema / (root)Previous value: -{ - "properties": { - "result": { - "type": "string" - } - }, - "required": [ - "result" - ], - "type": "object", - "x-fastmcp-wrap-result": true -}New value: +null
- Changed
semantic_search1 field changed- changed
Output schema / (root)Previous value: -{ - "properties": { - "result": { - "type": "string" - } - }, - "required": [ - "result" - ], - "type": "object", - "x-fastmcp-wrap-result": true -}New value: +null
- Changed
tags1 field changed- changed
Output schema / (root)Previous value: -{ - "properties": { - "result": { - "type": "string" - } - }, - "required": [ - "result" - ], - "type": "object", - "x-fastmcp-wrap-result": true -}New value: +null
- Changed
tool_activity1 field changed- changed
Output schema / (root)Previous value: -{ - "properties": { - "result": { - "type": "string" - } - }, - "required": [ - "result" - ], - "type": "object", - "x-fastmcp-wrap-result": true -}New value: +null
103 tool updates
v2.3.2- Removed
add_questions_to_form - Removed
add_slide - Removed
bulk_calendar_operations - Removed
check_drive_auth - Removed
cleanup_qdrant_data - Removed
compose_dynamic_email - Removed
create_calendar - Removed
create_doc - Removed
create_drive_file - Removed
create_event - Removed
create_form - Removed
create_gmail_filter - Removed
create_photos_album - Removed
create_presentation - Removed
create_sheet - Removed
create_spreadsheet - Removed
create_template_macro - Removed
delete_event - Removed
delete_gmail_filter - Removed
download_gmail_attachment - Removed
draft_gmail_forward - Removed
draft_gmail_message - Removed
draft_gmail_reply - Added
execute - Removed
export_and_download_presentation - Removed
fetch - Added
fetch_document - Removed
format_sheet_range - Removed
forward_gmail_message - Removed
get_doc_content - Removed
get_drive_file_content - Removed
get_event - Removed
get_form - Removed
get_form_response - Removed
get_gmail_filter - Removed
get_gmail_message_content - Removed
get_gmail_messages_content_batch - Removed
get_gmail_thread_content - Removed
get_people_contact_group_members - Removed
get_photo_details - Removed
get_photos_library_info - Removed
get_presentation_info - Removed
get_response_details - Added
get_schema - Removed
get_spreadsheet_info - Removed
get_tool_analytics - Removed
health_check - Removed
list_album_photos - Removed
list_calendars - Removed
list_docs_in_folder - Removed
list_drive_items - Removed
list_events - Removed
list_form_responses - Removed
list_gmail_filters - Removed
list_gmail_labels - Removed
list_messages - Removed
list_people_contact_labels - Removed
list_photos_albums - Removed
list_spaces - Removed
list_spreadsheets - Removed
make_drive_files_public - Removed
manage_credentials - Removed
manage_drive_files - Removed
manage_gmail_allow_list - Removed
manage_gmail_label - Removed
manage_people_contact_labels - Removed
manage_space - Removed
manage_tools - Removed
modify_event - Removed
modify_gmail_message_labels - Removed
modify_sheet_values - Removed
move_events_between_calendars - Removed
photos_batch_details - Removed
photos_optimized_album_sync - Removed
photos_performance_stats - Removed
photos_smart_search - Removed
publish_form_publicly - Removed
qdrant_search - Removed
read_sheet_values - Removed
reply_to_gmail_message - Added
search - Removed
search_docs - Removed
search_drive_files - Removed
search_gmail_messages - Removed
search_messages - Removed
search_photos - Removed
search_tool_history - Added
semantic_search - Removed
send_dynamic_card - Removed
send_gmail_message - Removed
send_message - Removed
set_form_publish_state - Removed
set_privacy_mode - Removed
share_drive_files - Removed
start_google_auth - Added
tags - Added
tool_activity - Removed
update_form_questions - Removed
update_slide_content - Removed
upload_folder_photos - Removed
upload_photos - Removed
upload_to_drive - Removed
verify_payment
96 tool updates
v2.2.1- First observed
add_questions_to_form - First observed
add_slide - First observed
bulk_calendar_operations - First observed
check_drive_auth - First observed
cleanup_qdrant_data - First observed
compose_dynamic_email - First observed
create_calendar - First observed
create_doc - First observed
create_drive_file - First observed
create_event - First observed
create_form - First observed
create_gmail_filter - First observed
create_photos_album - First observed
create_presentation - First observed
create_sheet - First observed
create_spreadsheet - First observed
create_template_macro - First observed
delete_event - First observed
delete_gmail_filter - First observed
download_gmail_attachment - First observed
draft_gmail_forward - First observed
draft_gmail_message - First observed
draft_gmail_reply - First observed
export_and_download_presentation - First observed
fetch - First observed
format_sheet_range - First observed
forward_gmail_message - First observed
get_doc_content - First observed
get_drive_file_content - First observed
get_event - First observed
get_form - First observed
get_form_response - First observed
get_gmail_filter - First observed
get_gmail_message_content - First observed
get_gmail_messages_content_batch - First observed
get_gmail_thread_content - First observed
get_people_contact_group_members - First observed
get_photo_details - First observed
get_photos_library_info - First observed
get_presentation_info - First observed
get_response_details - First observed
get_spreadsheet_info - First observed
get_tool_analytics - First observed
health_check - First observed
list_album_photos - First observed
list_calendars - First observed
list_docs_in_folder - First observed
list_drive_items - First observed
list_events - First observed
list_form_responses - First observed
list_gmail_filters - First observed
list_gmail_labels - First observed
list_messages - First observed
list_people_contact_labels - First observed
list_photos_albums - First observed
list_spaces - First observed
list_spreadsheets - First observed
make_drive_files_public - First observed
manage_credentials - First observed
manage_drive_files - First observed
manage_gmail_allow_list - First observed
manage_gmail_label - First observed
manage_people_contact_labels - First observed
manage_space - First observed
manage_tools - First observed
modify_event - First observed
modify_gmail_message_labels - First observed
modify_sheet_values - First observed
move_events_between_calendars - First observed
photos_batch_details - First observed
photos_optimized_album_sync - First observed
photos_performance_stats - First observed
photos_smart_search - First observed
publish_form_publicly - First observed
qdrant_search - First observed
read_sheet_values - First observed
reply_to_gmail_message - First observed
search_docs - First observed
search_drive_files - First observed
search_gmail_messages - First observed
search_messages - First observed
search_photos - First observed
search_tool_history - First observed
send_dynamic_card - First observed
send_gmail_message - First observed
send_message - First observed
set_form_publish_state - First observed
set_privacy_mode - First observed
share_drive_files - First observed
start_google_auth - First observed
update_form_questions - First observed
update_slide_content - First observed
upload_folder_photos - First observed
upload_photos - First observed
upload_to_drive - First observed
verify_payment
TDQS
Each tool has a clearly distinct role: tags for browsing categories, search for keyword discovery, get_schema for parameters, execute for running tools, semantic_search for past results, fetch_document for previewing stored content, and tool_activity for analytics. No two tools have overlapping purposes.
Names mix verbs (execute, search), nouns (tags, tool_activity), and verb-noun compounds (get_schema, fetch_document). There is no consistent verb_noun pattern across all tools, though they are all lowercase with underscores for multi-word names, making them still readable.
Seven tools is well-suited for a meta-server that wraps Google Workspace access. They cover discovery, schema lookup, execution, history search, document preview, and analytics without being excessive or sparse.
The set provides a complete workflow from discovering tools (search/tags) to understanding parameters (get_schema) to executing (execute) to auditing (semantic_search, fetch_document, tool_activity). The only minor gap is that actual Google Workspace tools are not exposed as first-class tool entries, but they are accessible via execute, so the surface is effectively complete.
Maintenance
Related MCP Connectors
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
Hosted MCP server with managed OAuth for 15+ toolkits: Google Workspace, Fitbit, Oura, Kalshi, etc.
MCP server for Argo RPG Platform — connects AI assistants to campaign data via OAuth2
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Related MCP Servers
- Apache 2.0
- AlicenseBqualityAmaintenanceMCP server integrating multiple Google Workspace services including Gmail, Calendar, Drive, Sheets, Docs, Tasks, People, Forms, and Slides, enabling users to manage emails, events, files, documents, and more through natural language.15MIT
- AlicenseBqualityCmaintenanceComprehensive Google Workspace MCP server with Gmail, Drive, Calendar, and Contacts integration.2614MIT
- FlicenseNot gradedqualityDmaintenanceAn MCP server that exposes 17 Google Workspace APIs (e.g., Gmail, Drive, Calendar) as auto-generated tools for AI assistants, enabling natural language control of Google services.-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/dipseth/google_workspace_fastmcp2'
If you have feedback or need assistance with the MCP directory API, please join our Discord server