Google Workspace
Build an MCP server with Google Calendar and Drive tools using Keycard delegated access
Build an MCP server with Calendar and Drive tools that let AI agents manage a user’s Google Workspace on their behalf.
Google Setup
Section titled “Google Setup”-
Copy your Keycard redirect URL
In Keycard Console, navigate to Zone Settings and copy the OAuth2 Redirect URL. You will need this when creating the Google OAuth App.
-
Create a Google OAuth App
In Google Cloud Console → APIs & Services → Credentials, create an OAuth 2.0 Client ID (application type: Web application). Add the redirect URL you copied from Keycard to Authorized redirect URIs. Note the Client ID and Client Secret.
Also enable the Calendar API and Drive API under APIs & Services → Enabled APIs.
-
Add Google from Resource Catalog
In Keycard Console, navigate to Resource Catalog and add Google Calendar and Google Drive. Enter the Client ID and Client Secret from step 2. This creates the Google OAuth provider and API resources.
-
Register your MCP server Resource
Navigate to Resources → Create Resource:
Field Value Resource Name Google Workspace MCP Server Resource Identifier http://localhost:8000/mcpCredential Provider Zone Provider -
Create an Application
Navigate to Applications → Create Application:
Field Value Provided Resource Google Workspace MCP Server (your MCP server) Dependencies Google Calendar API, Google Drive API After creating the Application, generate client credentials and save them.
Implementation
Section titled “Implementation”The implementation follows the same pattern as the GitHub server. The only difference is the API URL you pass to grant() and the API calls you make with the token.
pip install keycardai-fastmcp fastmcp httpxCreate a .env file:
KEYCARD_ZONE_ID=<your-zone-id>MCP_SERVER_URL=http://localhost:8000KEYCARD_CLIENT_ID=<your-client-id>KEYCARD_CLIENT_SECRET=<your-client-secret>The server setup is identical to GitHub: just change the server name. The tools file uses the same grant pattern with https://www.googleapis.com:
from keycardai.fastmcp import AccessContext, AuthProvider
GOOGLE_API = "https://www.googleapis.com"
def register_tools(mcp: FastMCP, auth_provider: AuthProvider): @mcp.tool() @auth_provider.grant(GOOGLE_API) async def list_calendar_events(ctx: Context, calendar_id: str = "primary") -> dict: """List events from a Google Calendar.""" access_context: AccessContext = await ctx.get_state("keycardai") token = access_context.access(GOOGLE_API).access_token
# Use token to call Google Calendar API async with httpx.AsyncClient() as client: response = await client.get( f"{GOOGLE_API}/calendar/v3/calendars/{calendar_id}/events", headers={"Authorization": f"Bearer {token}"}, params={"singleEvents": "true", "orderBy": "startTime"}, ) # ... process response
@mcp.tool() @auth_provider.grant(GOOGLE_API) async def list_drive_files(ctx: Context, q: str | None = None) -> dict: """List or search files in Google Drive.""" access_context: AccessContext = await ctx.get_state("keycardai") token = access_context.access(GOOGLE_API).access_token # Use token to call Google Drive APISee the full example with all tools, error handling, and Google Workspace file export logic: Python SDK examples
npm install @keycardai/mcp @modelcontextprotocol/sdk expressnpm install -D typescript @types/expressCreate a .env file:
KEYCARD_ZONE_URL=https://<your-zone-id>.keycard.cloudKEYCARD_CLIENT_ID=<your-client-id>KEYCARD_CLIENT_SECRET=<your-client-secret>PORT=8080The server setup is identical to GitHub: just change the server name. The tools file uses the same grant pattern with https://www.googleapis.com:
import type { Express } from "express";import type { AuthProvider, DelegatedRequest } from "@keycardai/mcp/server/auth/provider";
const GOOGLE_API = "https://www.googleapis.com";
export function registerGoogleRoutes(app: Express, authProvider: AuthProvider) { app.get("/api/calendar/events", authProvider.grant(GOOGLE_API), async (req, res) => { const { accessContext } = req as DelegatedRequest; if (accessContext.hasErrors()) { res.status(502).json({ error: "Token exchange failed" }); return; } const token = accessContext.access(GOOGLE_API).accessToken;
// Use token to call Google Calendar API const response = await fetch( `${GOOGLE_API}/calendar/v3/calendars/primary/events?singleEvents=true&orderBy=startTime`, { headers: { Authorization: `Bearer ${token}` } }, ); // ... process response });
app.get("/api/drive/files", authProvider.grant(GOOGLE_API), async (req, res) => { // Same pattern: grant → accessContext → token → API call });}See the full example with all tools, error handling, and Google Workspace file export logic: TypeScript SDK examples
Test It
Section titled “Test It”-
Start your server
Terminal window python server.pyTerminal window npx tsx server.ts -
Configure your agent
Add the MCP server to your agent configuration:
Cursor: add to
.cursor/mcp.json:{"mcpServers": {"google-mcp": {"url": "http://localhost:8000/mcp"}}}Claude Code: run in your terminal:
Terminal window claude mcp add --transport http google-mcp http://localhost:8000/mcp -
Authenticate
Restart your coding agent to detect the server. When prompted, complete the OAuth flow. Keycard will prompt you to sign in to your zone. This is a separate account from your Keycard Console login. If it’s your first time, click Sign up to create one. You will then be prompted to authorize Google Calendar and Drive access.
-
Try these prompts:
- “Show my calendar events for this week”
- “List my recent Drive files”
- “Get the content of the file named ‘Meeting Notes’”
-
Verify in Audit Logs
Check Keycard Console Audit Logs. You should see the same
users:authenticate,users:authorize, andcredentials:issueevents, with the identity chain showing your user and the Google Application.