A Model Context Protocol (MCP) server that provides secure integration with Google Drive, Docs, Sheets, Slides, and Calendar. It allows Claude Desktop and other MCP clients to manage files in Google Drive and calendar events through a standardized interface.
- Multi-format Support: Work with Google Docs, Sheets, Slides, Calendar, and regular files
- File Management: Create, update, delete, rename, move, copy, upload, and download files and folders
- Advanced Search: Search across your entire Google Drive
- Shared Drives Support: Full access to Google Shared Drives (formerly Team Drives) in addition to My Drive
- Folder Navigation: List and navigate through folder hierarchies with path support (e.g.,
/Work/Projects) - Google Docs Editing: Surgical text insertion/deletion, table management, image embedding, comments, and rich formatting
- Google Calendar: Full calendar management — list calendars, create/update/delete events, Google Meet integration
- MCP Resource Protocol: Files accessible as MCP resources for reading content
- Secure Authentication: OAuth 2.0 with automatic token refresh
This MCP server enables powerful file management workflows through natural language:
Create a new Google Doc called "Project Plan" in the folder /Work/Projects
with an outline for our Q1 initiatives including milestones and deliverables.
Search for files containing "budget" and organize them by moving each one
to the appropriate folder in your Drive hierarchy.
Create a Google Sheet called "Sales Analysis 2024" with columns for Date, Product,
Quantity, and Revenue to track your sales data.
Create a presentation called "Product Roadmap" with slides outlining
our Q1 milestones, key features, and timeline.
Update the "Team Contacts" spreadsheet with new employee information
by modifying specific cells or ranges with the provided data.
Search for documents in the /Reports folder and create a summary
document listing the files you found.
Create a Templates folder and add standard documents like
a Meeting Notes template, Project Proposal template,
and Budget Spreadsheet template.
- Node.js: Version 18 or higher (LTS recommended)
- Google Cloud Project: With the following APIs enabled:
- Google Drive API
- Google Docs API
- Google Sheets API
- Google Slides API
- Google Calendar API
- OAuth 2.0 Credentials: Desktop application type (Client ID only - no client secret required)
- Go to the Google Cloud Console
- Click "Select a project" > "New Project"
- Name your project (e.g., "Google Drive MCP")
- Note the Project ID for later
- In your project, go to "APIs & Services" > "Library"
- Search for and enable each of these APIs:
- Google Drive API
- Google Docs API
- Google Sheets API
- Google Slides API
- Google Calendar API
- Wait for each API to be enabled before proceeding
- Go to "APIs & Services" > "OAuth consent screen"
- Under 'Branding' fill in the required fields:
- App name: "My Personal Google Drive MCP"
- User support email: Your email
- Developer contact: Your email
- Under 'Audience':
- Choose "External" (default choice) or "Internal" for Google Workspace accounts
- Add your email as a test user
- Under 'Data Access' add scopes. The recommended set of scopes for best user experience is the following:
./auth/drive.file.../auth/documents.../auth/spreadsheets.../auth/presentations.../auth/drive.../auth/drive.readonly.../auth/calendar.../auth/calendar.events
- Go to "APIs & Services" > "Credentials"
- Click "+ CREATE CREDENTIALS" > "OAuth client ID"
- Application type: Desktop app (Important!)
- Name: "Google Drive MCP Client"
- Click "Create"
- Download the JSON file
- Rename it to
gcp-oauth.keys.json
You can run the server directly without installation:
# Run the server (authentication happens automatically on first run)
npx @piotr-agier/google-drive-mcp
# Optional: Run authentication manually if needed
npx @piotr-agier/google-drive-mcp auth-
Clone and install:
git clone https://github.com/piotr-agier/google-drive-mcp.git cd google-drive-mcp npm install -
Set up credentials:
# Copy the example file cp gcp-oauth.keys.example.json gcp-oauth.keys.json # Edit gcp-oauth.keys.json with your OAuth client ID
-
Authenticate (optional):
npm run auth
Note: Authentication happens automatically on first run of an MCP client if you skip this step.
-
Authenticate locally first - Docker containers cannot open browsers for OAuth:
# Using npx npx @piotr-agier/google-drive-mcp auth # Or using local installation npm run auth
-
Verify token location:
ls -la ~/.config/google-drive-mcp/tokens.json
-
Build the project (required before Docker build):
npm install npm run build
-
Build the Docker image:
docker build -t google-drive-mcp .
The scripts/docker-mcp.sh wrapper manages the container lifecycle — it creates, reuses, and replaces containers automatically. MCP clients invoke this script directly (see configuration below).
To verify the image works after a rebuild:
docker run --rm google-drive-mcp --helpUses a wrapper script that keeps a single named container running and reuses it across client restarts — faster startup and no container churn:
{
"mcpServers": {
"google-drive": {
"command": "/path/to/google-drive-mcp/scripts/docker-mcp.sh",
"env": {
"GOOGLE_DRIVE_OAUTH_CREDENTIALS": "$HOME/gcp-oauth.keys.json",
"GOOGLE_DRIVE_MCP_TOKEN_PATH": "$HOME/.config/google-drive-mcp/tokens.json"
}
}
}
}The script will:
- Create the container on first run
- Reuse the existing container on subsequent runs
- Automatically restart it if it was stopped
- Replace the container when the image has been rebuilt
Note: The container stays running in the background until explicitly stopped.
To stop it: docker stop google-drive-mcp
Creates and removes a new container on every client restart:
{
"mcpServers": {
"google-drive": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-v",
"/path/to/gcp-oauth.keys.json:/config/gcp-oauth.keys.json:ro",
"-v",
"/Users/yourname/.config/google-drive-mcp/tokens.json:/config/tokens.json",
"google-drive-mcp"
]
}
}
}Docker-specific notes:
- Uses
-ifor interactive mode (required for MCP stdio communication) - Uses
--rmto automatically remove the container after exit - No port mapping needed (MCP uses stdio, not HTTP)
- Environment variables are set in the Dockerfile
The server supports multiple methods for providing OAuth credentials (in order of priority):
export GOOGLE_DRIVE_OAUTH_CREDENTIALS="/path/to/your/gcp-oauth.keys.json"Place gcp-oauth.keys.json in the XDG config directory:
~/.config/google-drive-mcp/gcp-oauth.keys.json
This is the recommended location — it works reliably with npx, global installs, and local setups.
Place gcp-oauth.keys.json in the project root directory. This still works for local development but is unreliable with npx or global installs.
By default, the server requests a broad scope set for Drive/Docs/Sheets/Slides/Calendar. You can override requested scopes with:
export GOOGLE_DRIVE_MCP_SCOPES="drive.readonly,documents,spreadsheets"Notes:
- Comma-separated list.
- Values can be full scope URLs or short aliases:
drive,drive.file,drive.readonly,documents,spreadsheets,presentations,calendar,calendar.events. - Changing scopes usually requires re-authentication.
Authentication tokens are stored securely following the XDG Base Directory specification:
| Priority | Location | Configuration |
|---|---|---|
| 1 | Custom path | Set GOOGLE_DRIVE_MCP_TOKEN_PATH environment variable |
| 2 | XDG Config | $XDG_CONFIG_HOME/google-drive-mcp/tokens.json |
| 3 | Default | ~/.config/google-drive-mcp/tokens.json |
Security Notes:
- Tokens are created with secure permissions (0600)
- Never commit tokens to version control
- Tokens auto-refresh before expiration
- Google OAuth apps in "Testing" status have refresh tokens that expire after 7 days (Google's policy)
Add the server to your Claude Desktop configuration:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"google-drive": {
"command": "npx",
"args": ["@piotr-agier/google-drive-mcp"],
"env": {
"GOOGLE_DRIVE_OAUTH_CREDENTIALS": "/path/to/your/gcp-oauth.keys.json"
}
}
}
}{
"mcpServers": {
"google-drive": {
"command": "node",
"args": ["/absolute/path/to/google-drive-mcp/dist/index.js"],
"env": {
"GOOGLE_DRIVE_OAUTH_CREDENTIALS": "/path/to/your/gcp-oauth.keys.json"
}
}
}
}Note: Replace /path/to/your/gcp-oauth.keys.json with the actual path to your OAuth credentials file.
By default the server uses stdio transport (for local MCP clients like Claude Desktop). You can also run it as an HTTP server using the Streamable HTTP transport, which enables remote/hosted deployments and shared gateways.
google-drive-mcp start --transport http --port 3100 --host 127.0.0.1Or with environment variables:
MCP_TRANSPORT=http MCP_HTTP_PORT=3100 MCP_HTTP_HOST=127.0.0.1 google-drive-mcp startCLI flags take priority over environment variables.
| CLI Flag | Env Var | Default | Description |
|---|---|---|---|
--transport |
MCP_TRANSPORT |
stdio |
stdio or http |
--port |
MCP_HTTP_PORT |
3100 |
HTTP listen port |
--host |
MCP_HTTP_HOST |
127.0.0.1 |
HTTP bind address |
The HTTP endpoint is POST /mcp for JSON-RPC requests, GET /mcp for SSE streaming, and DELETE /mcp to close a session. After the initial initialize request, all subsequent requests must include the mcp-session-id header returned in the initialize response.
When binding to 127.0.0.1 (default), DNS rebinding protection is automatically enabled. For remote deployments (0.0.0.0), use service account or external token authentication and ensure the endpoint is behind a reverse proxy with TLS. Without authentication and TLS, anyone who can reach the port gets full access to the configured Google Drive account.
{
"mcpServers": {
"google-drive": {
"url": "http://localhost:3100/mcp"
}
}
}-
search - Search for files across Google Drive
query: Search terms (or raw Drive API query whenrawQuery=true)pageSize: Number of results per page (optional, default 50, max 100)pageToken: Pagination token for next page (optional)rawQuery: Passquerydirectly to the Drive API — enables operators likemodifiedTime,createdTime,mimeType,name contains, etc. (optional)
-
listFolder - List contents of a folder
folderId: Folder ID (optional, defaults to root)pageSize: Number of results (optional, max 100)pageToken: Pagination token (optional)
-
listSharedDrives - List available Google Shared Drives
pageSize: Number of drives to return (optional, default 50, max 100)pageToken: Pagination token (optional)
-
createTextFile - Create a text or markdown file
name: File name (must end with .txt or .md)content: File contentparentFolderId: Parent folder ID (optional)
-
updateTextFile - Update existing text file
fileId: File ID to updatecontent: New contentname: New name (optional)
-
deleteItem - Move a file or folder to trash (not a permanent deletion - items can be restored from Google Drive trash)
itemId: Item ID to move to trash
-
renameItem - Rename a file or folder
itemId: Item ID to renamenewName: New name
-
moveItem - Move a file or folder
itemId: Item ID to movedestinationFolderId: Destination folder ID
-
copyFile - Create a copy of a Google Drive file or document
fileId: ID of the file to copynewName: Name for the copied file (optional, defaults to "Copy of [original name]")parentFolderId: Destination folder ID (optional, defaults to same location)
-
listPermissions - List current sharing permissions on a file/folder
fileId: File or folder ID
-
addPermission - Add a new permission to a file/folder
fileId: File or folder IDtype: Permission target type (user,group,domain,anyone)role: Permission role (reader,commenter,writer,fileOrganizer,organizer,owner)emailAddress: Required foruser/grouptypesdomain: Required fordomaintypesendNotificationEmail: Send notification email (optional)
-
updatePermission - Update role for an existing permission
fileId: File or folder IDpermissionId: Permission IDrole: New role
-
removePermission - Remove a permission from a file/folder
fileId: File or folder IDpermissionId: Permission ID (optional ifemailAddressis provided)emailAddress: Email to find permission by (optional fallback)
-
shareFile - Share file with a user email (idempotent helper)
fileId: File or folder IDemailAddress: Recipient emailrole: Role (reader,commenter,writer)sendNotificationEmail: Send notification email (optional)
-
getRevisions - List revisions for a file
fileId: File IDpageSize: Max revisions to return (optional)
-
restoreRevision - Restore a file from a selected revision (safety-confirmed)
fileId: File IDrevisionId: Revision ID to restoreconfirm: Must betrueto execute restore
- authGetStatus - Show token/scopes/auth health diagnostics (machine + human readable)
- authListScopes - Show configured/requested scopes, granted scopes, missing scopes, and presets
- authTestFileAccess - Test Drive access (optionally against a specific
fileId)
-
createShortcut - Create a shortcut to a file or folder
targetFileId: File or folder ID to link toparentFolderId: Folder ID or path where the shortcut will be created (optional)shortcutName: Custom shortcut name (optional, defaults to original file name)
-
lockFile - Lock a file by setting content restrictions
fileId: File ID to lockreason: Reason shown to editors (optional)ownerRestricted: Only the owner can unlock (optional, default false)
-
unlockFile - Remove content restrictions from a locked file
fileId: File ID to unlock
-
uploadFile - Upload a local file (any type: image, audio, video, PDF, etc.) to Google Drive
localPath: Absolute path to the local filename: File name in Drive (optional, defaults to local filename)parentFolderId: Parent folder ID or path (optional, e.g., '/Work/Projects')mimeType: MIME type (optional, auto-detected from extension)convertToGoogleFormat: Convert uploaded file to native Google Workspace format (optional, default: false). When enabled, Office files are automatically converted:.docx/.doc→ Google Doc.xlsx/.xls→ Google Sheet.pptx/.ppt→ Google Slides- File extension is stripped from the name automatically (e.g.,
report.docxbecomesreport)
-
downloadFile - Download a Google Drive file to a local path
fileId: Google Drive file IDlocalPath: Absolute local path to save the file (can be a directory or full file path)exportMimeType: For Google Workspace files, MIME type to export as (optional, e.g., 'application/pdf', 'text/csv')overwrite: Whether to overwrite existing files (optional, default: false)
-
convertPdfToGoogleDoc - Convert a PDF already stored in Drive into an editable Google Doc
fileId: Source PDF file IDnewName: Optional destination doc nameparentFolderId: Optional destination folder
-
bulkConvertFolderPdfs - Convert all PDFs in a folder and return per-file success/failure summary
folderId: Source folder IDmaxResults: Maximum PDFs to process (optional, default: 100)continueOnError: Continue processing after individual failures (optional, default: true)
-
uploadPdfWithSplit - Upload a local PDF, optionally split into chunked PDF parts before upload
localPath: Absolute local path to PDFsplit: Enable split mode metadata output (optional, default: false)maxPagesPerChunk: Advisory chunk size for split planning (optional)parentFolderId: Optional destination foldernamePrefix: Optional uploaded file name prefix
- createFolder - Create a new folder
name: Folder nameparent: Parent folder ID or path (optional)
-
createGoogleDoc - Create a Google Doc
name: Document namecontent: Document contentparentFolderId: Parent folder ID (optional)
-
updateGoogleDoc - Replace all content in a Google Doc
documentId: Document IDcontent: New content
-
readGoogleDoc - Read content of a Google Doc with format options
documentId: Document IDformat: Output format —text,json, ormarkdown(optional, default: text)maxLength: Maximum characters to return (optional)
-
getGoogleDocContent - Get document content with text indices for formatting
documentId: Document IDincludeFormatting: Include font, style, and color info for each text span (optional, default: false)
-
listDocumentTabs - List all tabs in a Google Doc with their IDs and hierarchy
documentId: Document IDincludeContent: Include content summary (character count) for each tab (optional)
-
addDocumentTab - Add a new tab in a Google Doc
documentId: Document IDtitle: Tab title
-
renameDocumentTab - Rename an existing tab in a Google Doc
documentId: Document IDtabId: Tab IDtitle: New tab title
-
insertSmartChip - Insert a person smart chip (mention) at a document index. Only person chips are supported by the Docs API; date and file chips are read-only.
documentId: Document IDindex: Insertion index (1-based)chipType:person(only supported type)personEmail: Email address for the person mention
-
readSmartChips - Read smart chip-like elements (person mentions, rich links, date chips) from the default tab of a document. Only the default tab is scanned; other tabs are not included.
documentId: Document ID
-
createFootnote - Create a footnote in a Google Doc. Footnotes cannot be inserted inside equations, headers, footers, or other footnotes.
documentId: Document IDindex: 1-based character index where the footnote reference should be inserted (optional — provide this orendOfSegment)endOfSegment: If true, insert footnote at the end of the document body (optional — provide this orindex)content: Optional text content for the footnote body
-
listGoogleDocs - List Google Documents with optional filtering
query: Search query to filter by name or content (optional)maxResults: Maximum documents to return, 1-100 (optional, default: 20)orderBy: Sort order —name,modifiedTime, orcreatedTime(optional)
-
getDocumentInfo - Get detailed metadata about a specific Google Document
documentId: Document ID
-
insertText - Insert text at a specific index (doesn't replace entire doc)
documentId: Document IDtext: Text to insertindex: Position to insert at (1-based)
-
deleteRange - Delete content between start and end indices
documentId: Document IDstartIndex: Start index (1-based, inclusive)endIndex: End index (exclusive)
-
applyTextStyle - Apply text formatting (bold, italic, color, etc.) to a range or found text
documentId: Document ID- Target (use one):
startIndex+endIndexORtextToFind+matchInstance bold,italic,underline,strikethrough: Text styling (optional)fontSize: Font size in points (optional)fontFamily: Font family name (optional)foregroundColor: Hex color, e.g.,#FF0000(optional)backgroundColor: Hex background color (optional)linkUrl: URL for hyperlink (optional)
-
applyParagraphStyle - Apply paragraph formatting
documentId: Document ID- Target (use one):
startIndex+endIndexORtextToFind+matchInstanceORindexWithinParagraph namedStyleType: NORMAL_TEXT, TITLE, SUBTITLE, HEADING_1 through HEADING_6 (optional)alignment: START, CENTER, END, or JUSTIFIED (optional)indentStart,indentEnd: Indent in points (optional)spaceAbove,spaceBelow: Spacing in points (optional)keepWithNext: Keep with next paragraph (optional)
-
formatGoogleDocText - Alias for
applyTextStyle(compatibility helper)- Same parameters as
applyTextStyle
- Same parameters as
-
formatGoogleDocParagraph - Alias for
applyParagraphStyle(compatibility helper)- Same parameters as
applyParagraphStyle
- Same parameters as
-
createParagraphBullets - Add or remove bullet points / numbered lists on paragraphs
documentId: Document ID- Target (use one):
startIndex+endIndexORtextToFind+matchInstance bulletPreset: Bullet style preset (optional, default:BULLET_DISC_CIRCLE_SQUARE). Available presets:- Bullet styles:
BULLET_DISC_CIRCLE_SQUARE,BULLET_DIAMONDX_ARROW3D_SQUARE,BULLET_CHECKBOX,BULLET_ARROW_DIAMOND_DISC,BULLET_STAR_CIRCLE_SQUARE,BULLET_ARROW3D_CIRCLE_SQUARE,BULLET_LEFTTRIANGLE_DIAMOND_DISC - Numbered styles:
NUMBERED_DECIMAL_ALPHA_ROMAN,NUMBERED_DECIMAL_ALPHA_ROMAN_PARENS,NUMBERED_DECIMAL_NESTED,NUMBERED_UPPERALPHA_ALPHA_ROMAN,NUMBERED_UPPERROMAN_UPPERALPHA_DECIMAL,NUMBERED_ZERODECIMAL_ALPHA_ROMAN - Remove bullets:
NONE— removes existing bullets/numbering from the targeted paragraphs
- Bullet styles:
-
findAndReplaceInDoc - Find and replace text across a Google Doc
documentId: Document IDfindText: Text to findreplaceText: Replacement textmatchCase: Case-sensitive match (optional, default: false)dryRun: Only report estimated matches, don’t modify document (optional, default: false)
-
insertTable - Insert a new table at a given index
documentId: Document IDrows: Number of rowscolumns: Number of columnsindex: Position to insert at (1-based)
-
editTableCell - Edit content and/or style of a specific table cell
documentId: Document IDtableStartIndex: Starting index of the table elementrowIndex: Row index (0-based)columnIndex: Column index (0-based)textContent: New text content (optional)bold,italic,fontSize,alignment: Cell styling (optional)
-
insertImageFromUrl - Insert an inline image from a publicly accessible URL
documentId: Document IDimageUrl: Publicly accessible URL to the imageindex: Position to insert at (1-based)width,height: Image dimensions in points (optional)
-
insertLocalImage - Upload a local image file to Drive and insert it into a document
documentId: Document IDlocalImagePath: Absolute path to the local image fileindex: Position to insert at (1-based)width,height: Image dimensions in points (optional)uploadToSameFolder: Upload to same folder as document (optional, default: true)
-
listComments - List all comments in a Google Document with position context, character offsets, and full reply chains
documentId: Document IDincludeDeleted: Include deleted comments (optional, default: false)pageSize: Max comments to return, 1-100 (optional, default: 100)pageToken: Token for next page of results (optional)- Returns surrounding context and Docs API character offsets for each comment using a two-tiered approach (Docs API text matching, DOCX export fallback for ambiguous matches)
-
getComment - Get a specific comment with its full thread of replies
documentId: Document IDcommentId: Comment ID
-
addComment - Add a comment anchored to a specific text range
documentId: Document IDstartIndex: Start index (1-based)endIndex: End index (exclusive)commentText: The comment content
-
replyToComment - Add a reply to an existing comment
documentId: Document IDcommentId: Comment ID to reply toreplyText: The reply contentresolve: Set totrueto resolve the comment thread after replying (optional, default: false)
-
deleteComment - Delete a comment from the document
documentId: Document IDcommentId: Comment ID to delete
-
createGoogleSheet - Create a Google Sheet
name: Spreadsheet namedata: 2D array of cell valuesparentFolderId: Parent folder ID (optional)valueInputOption:RAW(default, safe) orUSER_ENTERED(evaluates formulas) (optional)
-
updateGoogleSheet - Update a Google Sheet
spreadsheetId: Spreadsheet IDrange: Range to update (e.g., 'Sheet1!A1:C10')data: 2D array of new valuesvalueInputOption:RAW(default, safe) orUSER_ENTERED(evaluates formulas) (optional)
-
getGoogleSheetContent - Get spreadsheet content with cell information
spreadsheetId: Spreadsheet IDrange: Range to get (e.g., 'Sheet1!A1:C10')
-
getSpreadsheetInfo - Get detailed information about a spreadsheet including all sheets/tabs
spreadsheetId: Spreadsheet ID
-
appendSpreadsheetRows - Append rows to the end of a sheet
spreadsheetId: Spreadsheet IDrange: A1 notation range indicating where to append (e.g., 'A1' or 'Sheet1!A1')values: 2D array of values to appendvalueInputOption:RAWorUSER_ENTERED(optional, default: USER_ENTERED)
-
addSpreadsheetSheet - Add a new sheet/tab to an existing spreadsheet
-
addSheet - Alias for
addSpreadsheetSheetspreadsheetId: Spreadsheet IDsheetTitle: Title for the new sheet
-
listSheets - List tabs/sheets in a spreadsheet
spreadsheetId: Spreadsheet ID
-
renameSheet - Rename a sheet/tab by
sheetIdspreadsheetId: Spreadsheet IDsheetId: Sheet IDnewTitle: New title
-
deleteSheet - Delete a sheet/tab by
sheetIdspreadsheetId: Spreadsheet IDsheetId: Sheet ID
-
addDataValidation - Add data validation rules to a range
spreadsheetId: Spreadsheet IDrange: A1 range (e.g.,Sheet1!A1:A10)conditionType:ONE_OF_LIST,NUMBER_GREATER,NUMBER_LESS, orTEXT_CONTAINSvalues: Condition values (e.g. list items, threshold)strict: Reject invalid values (optional, default:true)showCustomUi: Show dropdown/custom UI (optional, default:true)
-
protectRange - Protect a range in a spreadsheet
spreadsheetId: Spreadsheet IDrange: A1 rangedescription: Protection description (optional)warningOnly: Warn instead of enforce (optional, default:false)
-
addNamedRange - Create a named range
spreadsheetId: Spreadsheet IDname: Named range namerange: A1 range
-
listGoogleSheets - List Google Spreadsheets with optional filtering
query: Search query to filter by name or content (optional)maxResults: Maximum spreadsheets to return, 1-100 (optional, default: 20)orderBy: Sort order —name,modifiedTime, orcreatedTime(optional)
-
formatGoogleSheetCells - Format cell properties
spreadsheetId: Spreadsheet IDrange: Range to format (e.g., 'A1:C10')backgroundColor: Cell background color (RGB 0-1) (optional)horizontalAlignment: LEFT, CENTER, or RIGHT (optional)verticalAlignment: TOP, MIDDLE, or BOTTOM (optional)wrapStrategy: OVERFLOW_CELL, CLIP, or WRAP (optional)
-
formatGoogleSheetText - Apply text formatting to cells
spreadsheetId: Spreadsheet IDrange: Range to format (e.g., 'A1:C10')bold,italic,strikethrough,underline: Text styling (optional)fontSize: Font size in points (optional)fontFamily: Font name (optional)foregroundColor: Text color (RGB 0-1) (optional)
-
formatGoogleSheetNumbers - Apply number/date formatting
spreadsheetId: Spreadsheet IDrange: Range to format (e.g., 'A1:C10')pattern: Format pattern (e.g., '#,##0.00', 'yyyy-mm-dd', '$#,##0.00', '0.00%')type: NUMBER, CURRENCY, PERCENT, DATE, TIME, DATE_TIME, or SCIENTIFIC (optional)
-
setGoogleSheetBorders - Configure cell borders
spreadsheetId: Spreadsheet IDrange: Range to format (e.g., 'A1:C10')style: SOLID, DASHED, DOTTED, or DOUBLEwidth: Border thickness 1-3 (optional)color: Border color (RGB 0-1) (optional)top,bottom,left,right: Apply to specific borders (optional)innerHorizontal,innerVertical: Apply to inner borders (optional)
-
mergeGoogleSheetCells - Merge cells in a range
spreadsheetId: Spreadsheet IDrange: Range to merge (e.g., 'A1:C3')mergeType: MERGE_ALL, MERGE_COLUMNS, or MERGE_ROWS
-
addGoogleSheetConditionalFormat - Add conditional formatting rules
spreadsheetId: Spreadsheet IDrange: Range to apply formatting (e.g., 'A1:C10')condition: Condition configurationtype: NUMBER_GREATER, NUMBER_LESS, TEXT_CONTAINS, TEXT_STARTS_WITH, TEXT_ENDS_WITH, or CUSTOM_FORMULAvalue: Value to compare or formula
format: Format to apply when condition is truebackgroundColor: Cell color (RGB 0-1) (optional)textFormat: Text formatting with bold and foregroundColor (optional)
-
createGoogleSlides - Create a presentation
name: Presentation nameslides: Array of slides with title and contentparentFolderId: Parent folder ID (optional)
-
updateGoogleSlides - Update an existing presentation
presentationId: Presentation IDslides: Array of slides with title and content (replaces all existing slides)
-
getGoogleSlidesContent - Get presentation content with element IDs
presentationId: Presentation IDslideIndex: Specific slide index (optional)
-
formatGoogleSlidesText - Apply text formatting to slide elements
presentationId: Presentation IDobjectId: Element IDstartIndex/endIndex: Text range (optional, 0-based)bold,italic,underline,strikethrough: Text styling (optional)fontSize: Font size in points (optional)fontFamily: Font name (optional)foregroundColor: Text color (RGB 0-1) (optional)
-
formatGoogleSlidesParagraph - Apply paragraph formatting
presentationId: Presentation IDobjectId: Element IDalignment: START, CENTER, END, or JUSTIFIED (optional)lineSpacing: Line spacing multiplier (optional)bulletStyle: NONE, DISC, ARROW, SQUARE, DIAMOND, STAR, or NUMBERED (optional)
-
styleGoogleSlidesShape - Style shapes and elements
presentationId: Presentation IDobjectId: Shape IDbackgroundColor: Fill color (RGBA 0-1) (optional)outlineColor: Border color (RGB 0-1) (optional)outlineWeight: Border thickness in points (optional)outlineDashStyle: SOLID, DOT, DASH, DASH_DOT, LONG_DASH, or LONG_DASH_DOT (optional)
-
setGoogleSlidesBackground - Set slide background color
presentationId: Presentation IDpageObjectIds: Array of slide IDsbackgroundColor: Background color (RGBA 0-1)
-
createGoogleSlidesTextBox - Create formatted text box
presentationId: Presentation IDpageObjectId: Slide IDtext: Text contentx,y,width,height: Position/size in EMU (1/360000 cm)fontSize,bold,italic: Text formatting (optional)
-
createGoogleSlidesShape - Create styled shape
presentationId: Presentation IDpageObjectId: Slide IDshapeType: RECTANGLE, ELLIPSE, DIAMOND, TRIANGLE, STAR, ROUND_RECTANGLE, or ARROWx,y,width,height: Position/size in EMUbackgroundColor: Fill color (RGBA 0-1) (optional)
-
getGoogleSlidesSpeakerNotes - Get speaker notes from a slide
presentationId: Presentation IDslideIndex: Slide index (0-based)
-
updateGoogleSlidesSpeakerNotes - Update or set speaker notes for a slide
presentationId: Presentation IDslideIndex: Slide index (0-based)notes: The speaker notes content to set
-
deleteGoogleSlide - Delete a slide by object ID
presentationId: Presentation IDslideObjectId: Slide object ID
-
duplicateSlide - Duplicate a slide by object ID
presentationId: Presentation IDslideObjectId: Slide object ID
-
reorderSlides - Reorder slides by object IDs and insertion index
presentationId: Presentation IDslideObjectIds: Array of slide object IDs to moveinsertionIndex: Target insertion index
-
replaceAllTextInSlides - Replace text across a presentation
presentationId: Presentation IDcontainsText: Text to findreplaceText: Replacement textmatchCase: Match case (optional, default:false)
-
exportSlideThumbnail - Export a slide thumbnail URL (PNG/JPEG, SMALL/MEDIUM/LARGE)
presentationId: Presentation IDslideObjectId: Slide object IDmimeType:PNGorJPEG(optional, default:PNG)size:SMALL,MEDIUM, orLARGE(optional, default:LARGE)
-
insertSlidesImageFromUrl - Insert an image into a slide from a public URL
presentationId: Presentation IDpageObjectId: Slide/page object IDimageUrl: Public image URLx,y,width,height: Position and size in EMU (optional)
-
getSlideElementInfo - Get position, size, and transform details for slide elements
presentationId: Presentation IDslideObjectId: Slide object ID (optional; omit for all slides)
-
moveSlideElement - Move or resize a slide element
presentationId: Presentation IDobjectId: Element object IDx,y,width,height: New position and/or size in EMU (optional)
-
deleteSlideElement - Delete an element from a slide
presentationId: Presentation IDobjectId: Element object ID
-
insertSlidesLocalImage - Upload a local image and insert it into a slide
presentationId: Presentation IDpageObjectId: Slide/page object IDlocalImagePath: Absolute local image pathx,y,width,height: Position and size in EMU (optional)
-
listCalendars - List all accessible Google Calendars
showHidden: Include hidden calendars (optional, default: false)
-
getCalendarEvents - Get events from a calendar with optional filtering
calendarId: Calendar ID (optional, default: primary)timeMin: Start of time range, RFC3339 (optional, e.g., '2024-01-01T00:00:00Z')timeMax: End of time range, RFC3339 (optional)query: Free text search in events (optional)maxResults: Maximum events to return, 1-250 (optional, default: 50)singleEvents: Expand recurring events into instances (optional, default: true)orderBy: Sort order —startTimeorupdated(optional, default: startTime)
-
getCalendarEvent - Get a single calendar event by ID
eventId: Event IDcalendarId: Calendar ID (optional, default: primary)
-
createCalendarEvent - Create a new calendar event with Google Meet support
summary: Event titlestart: Start time (dateTimefor timed events,datefor all-day, optionaltimeZone)end: End time (same format as start)calendarId: Calendar ID (optional, default: primary)description: Event description (optional)location: Event location (optional)attendees: Array of email addresses (optional)sendUpdates:all,externalOnly, ornone(optional, default: none)conferenceType:hangoutsMeetto add Google Meet link (optional)recurrence: Array of RRULE strings for recurring events (optional)visibility:default,public,private, orconfidential(optional)
-
updateCalendarEvent - Update an existing calendar event
eventId: Event IDcalendarId: Calendar ID (optional, default: primary)summary,description,location: Updated fields (optional)start,end: Updated times (optional)attendees: Updated attendee emails, replaces existing (optional)sendUpdates:all,externalOnly, ornone(optional, default: none)
-
deleteCalendarEvent - Delete a calendar event
eventId: Event IDcalendarId: Calendar ID (optional, default: primary)sendUpdates: Send cancellation notifications (optional, default: none)
For hosted, containerized, or CI/CD deployments where a browser-based OAuth flow is not available, the server supports two alternative authentication modes. They are checked in priority order before falling back to the default local OAuth flow.
Set the standard GOOGLE_APPLICATION_CREDENTIALS environment variable to point to a service account JSON key file. Best for server-to-server, CI/CD, and container deployments.
{
"mcpServers": {
"google-drive": {
"command": "npx",
"args": ["@piotr-agier/google-drive-mcp"],
"env": {
"GOOGLE_APPLICATION_CREDENTIALS": "/path/to/service-account-key.json"
}
}
}
}Note: The service account must have access to the Google Drive files/folders you want to work with. For Shared Drives, grant the service account's email address the appropriate permissions.
Provide a pre-obtained OAuth access token via GOOGLE_DRIVE_MCP_ACCESS_TOKEN. This is useful when an external service handles the OAuth flow (e.g., a web app that obtains tokens on behalf of the user).
Access token only (no auto-refresh — token will eventually expire):
{
"mcpServers": {
"google-drive": {
"command": "npx",
"args": ["@piotr-agier/google-drive-mcp"],
"env": {
"GOOGLE_DRIVE_MCP_ACCESS_TOKEN": "ya29.a0AfH6SM..."
}
}
}
}With refresh token (recommended — enables automatic token refresh):
{
"mcpServers": {
"google-drive": {
"command": "npx",
"args": ["@piotr-agier/google-drive-mcp"],
"env": {
"GOOGLE_DRIVE_MCP_ACCESS_TOKEN": "ya29.a0AfH6SM...",
"GOOGLE_DRIVE_MCP_REFRESH_TOKEN": "1//0dx...",
"GOOGLE_DRIVE_MCP_CLIENT_ID": "123456789.apps.googleusercontent.com",
"GOOGLE_DRIVE_MCP_CLIENT_SECRET": "GOCSPX-..."
}
}
}
}| Variable | Required | Description |
|---|---|---|
GOOGLE_DRIVE_MCP_ACCESS_TOKEN |
Yes (activates mode) | Google OAuth access token |
GOOGLE_DRIVE_MCP_REFRESH_TOKEN |
No | Refresh token for auto-refresh |
GOOGLE_DRIVE_MCP_CLIENT_ID |
Required with refresh token | OAuth client ID |
GOOGLE_DRIVE_MCP_CLIENT_SECRET |
Required with refresh token | OAuth client secret |
If neither of the above modes is configured, the server uses the existing browser-based OAuth flow. See below for details.
The server uses OAuth 2.0 for secure authentication:
- Server detects missing tokens and starts local auth server
- Your browser opens to Google's consent page
- Grant the requested permissions
- Tokens are saved securely to
~/.config/google-drive-mcp/tokens.json - Server continues startup
- Automatic Refresh: Tokens refresh automatically before expiration
- Secure Storage: Tokens stored with 0600 permissions
- Migration: Legacy tokens are automatically migrated to secure location
Run the auth command when you need to:
- Switch Google accounts
- Refresh expired tokens (Google expires refresh tokens after 7 days for apps in "Testing" status)
- Recover from revoked access
# Using npx
npx @piotr-agier/google-drive-mcp auth
# Using local installation
npm run auth- No Client Secrets: Desktop OAuth flow works with client ID only
- Secure Token Storage: Tokens stored with 0600 permissions in XDG-compliant location
- Scoped Access: Minimal permissions requested (drive.file, documents, spreadsheets, presentations, calendar)
- Local Execution: All processing happens on your machine
- Automatic Token Refresh: Reduces need for re-authentication
- Token Migration: Legacy tokens automatically moved to secure location
-
Never commit credentials: Add to
.gitignore:gcp-oauth.keys.json client_secret*.json .config/ -
Use environment variables for production:
export GOOGLE_DRIVE_OAUTH_CREDENTIALS="/secure/path/credentials.json" export GOOGLE_DRIVE_MCP_TOKEN_PATH="/secure/path/tokens.json"
-
Monitor access:
- Check recent activity in Google Drive
- Review OAuth app permissions regularly
If you need to revoke the Google Drive MCP's access to your Google account:
- Visit Google Account Permissions
- Find "Google Drive MCP" or your custom app name in the list
- Click on it and select "Remove Access"
- Clear local tokens to complete the revocation:
rm ~/.config/google-drive-mcp/tokens.json
After revoking access, you'll need to re-authenticate the next time you use the server.
OAuth credentials not found. Please provide credentials using one of these methods:
1. Config directory (recommended):
Place your gcp-oauth.keys.json file in: ~/.config/google-drive-mcp/
2. Environment variable:
export GOOGLE_DRIVE_OAUTH_CREDENTIALS="/path/to/gcp-oauth.keys.json"
Solution:
- Download credentials from Google Cloud Console
- Place the file in
~/.config/google-drive-mcp/gcp-oauth.keys.json(recommended), or set the environment variable - Ensure the file has proper read permissions
Possible causes:
- Wrong credential type: Must be "Desktop app", not "Web application"
- Port blocked: Ports 3000-3004 must be available
- Test user not added: Add your email in OAuth consent screen
Solution:
# Check if ports are in use
lsof -i :3000-3004
# Kill processes if needed
kill -9 <PID>
# Re-run authentication
npx @piotr-agier/google-drive-mcp authFor Google OAuth apps in "Testing" status:
- Google automatically expires refresh tokens after 7 days
- You'll need to re-authenticate weekly until you publish your app
Solution:
# Clear old tokens and re-authenticate
rm ~/.config/google-drive-mcp/tokens.json
npx @piotr-agier/google-drive-mcp authFor production:
- Move app to "Published" status in Google Cloud Console
- Complete OAuth verification process
If you updated the OAuth scopes but still get errors:
- Google caches app authorizations even after removing local tokens
- The app might be using old/limited scopes
Solution:
- Go to Google Account Permissions
- Find and remove access for "Google Drive MCP"
- Clear local tokens:
rm ~/.config/google-drive-mcp/tokens.json - Re-authenticate to grant all required scopes
- Verify the consent screen shows ALL scopes including full Drive access
Error: Google Sheets API has not been used in project...
Solution:
- Go to Google Cloud Console
- Select your project
- Navigate to "APIs & Services" > "Library"
- Search and enable the missing API
- Wait 1-2 minutes for propagation
Check scopes in your credentials:
- Need drive.file or drive scope
- Need docs, sheets, slides scopes for respective services
Solution:
- Re-create OAuth credentials with correct scopes
- Re-authenticate after updating credentials
Google API Quotas:
- Drive API: 12,000 requests per minute
- Docs/Sheets/Slides: 300 requests per minute
Solution:
- Implement exponential backoff
- Batch operations where possible
- Check quota usage in Google Cloud Console
Problem: The MCP server in Docker shows authentication errors even though you have valid tokens.
Cause: OAuth flow requires browser access, which isn't available in Docker containers.
Solution:
# 1. Authenticate outside Docker first
npx @piotr-agier/google-drive-mcp auth
# 2. Verify tokens exist
ls -la ~/.config/google-drive-mcp/tokens.json
# 3. Rebuild the image and restart the client
docker build -t google-drive-mcp .
# The client will invoke scripts/docker-mcp.sh, which auto-replaces the stale containerProblem: Docker build fails with tsc: not found or similar errors.
Solution:
# Build the project locally first
npm install
npm run build
# Then build Docker image
docker build -t google-drive-mcp .The Dockerfile expects the dist/ directory to exist from your local build.
Problem: Tokens can't refresh inside the container.
Solution: Ensure the token file is mounted with write permissions:
# Correct: tokens can be updated
-v "$HOME/.config/google-drive-mcp/tokens.json":/config/tokens.json
# Wrong: read-only mount prevents token refresh
-v "$HOME/.config/google-drive-mcp/tokens.json":/config/tokens.json:roEnable detailed logging:
# Set debug environment variable
export DEBUG=google-drive-mcp:*
npx @piotr-agier/google-drive-mcp- Check logs: Server logs errors to stderr
- Verify setup: Run
npx @piotr-agier/google-drive-mcp help - Test auth: Run
npx @piotr-agier/google-drive-mcp auth - Report issues: GitHub Issues
google-drive-mcp/
├── src/ # Source code
│ ├── index.ts # Main server implementation
│ ├── auth.ts # Main authentication module
│ ├── auth/ # Authentication components
│ │ ├── client.ts # OAuth2 client setup
│ │ ├── externalAuth.ts # Service account & external token auth
│ │ ├── server.ts # Local auth server
│ │ ├── tokenManager.ts # Token storage and validation
│ │ └── utils.ts # Auth utilities
│ ├── tools/ # Tool implementations by service
│ │ ├── drive.ts # File management tools
│ │ ├── docs.ts # Google Docs tools
│ │ ├── sheets.ts # Google Sheets tools
│ │ ├── slides.ts # Google Slides tools
│ │ └── calendar.ts # Google Calendar tools
│ ├── utils.ts # Shared utility functions
│ ├── types.ts # TypeScript type definitions
│ └── download-file.ts # File download helper
├── dist/ # Compiled JavaScript (generated)
├── scripts/ # Build scripts
│ └── build.js # Custom build script
├── gcp-oauth.keys.json # OAuth credentials (create from example)
├── gcp-oauth.keys.example.json # Example credentials file
├── package.json # NPM package configuration
├── tsconfig.json # TypeScript configuration
├── LICENSE # MIT license
└── README.md # This file
npm run build # Compile TypeScript
npm run watch # Compile and watch for changes
npm run typecheck # Type checking without compilationnpm start- Start the compiled servernpm run auth- Run authentication flownpm run build- Build the project (runs typecheck + custom build script)npm run watch- Build and watch for changesnpm run typecheck- Run TypeScript type checking onlynpm run lint- Run TypeScript type checking (alias for typecheck)npm run prepare- Auto-runs build before npm publishnpm test- Run unit tests
Credentials (required - use one of these methods):
| Variable | Description | Example |
|---|---|---|
GOOGLE_DRIVE_OAUTH_CREDENTIALS |
Path to your OAuth credentials JSON file | /home/user/secrets/oauth.json |
| (or place file at) | Config directory (recommended): ~/.config/google-drive-mcp/gcp-oauth.keys.json |
~/.config/google-drive-mcp/gcp-oauth.keys.json |
| (or place file at) | Project root (legacy fallback): gcp-oauth.keys.json |
./gcp-oauth.keys.json |
Optional (for customization):
| Variable | Description | Default | Example |
|---|---|---|---|
GOOGLE_DRIVE_MCP_TOKEN_PATH |
Override token storage location | ~/.config/google-drive-mcp/tokens.json |
/custom/path/tokens.json |
DEBUG |
Enable debug logging | (disabled) | google-drive-mcp:* |
External Authentication (alternative to local OAuth flow):
| Variable | Description | Example |
|---|---|---|
GOOGLE_APPLICATION_CREDENTIALS |
Path to service account JSON key file | /path/to/service-account.json |
GOOGLE_DRIVE_MCP_ACCESS_TOKEN |
Pre-obtained OAuth access token | ya29.a0AfH6SM... |
GOOGLE_DRIVE_MCP_REFRESH_TOKEN |
Refresh token for auto-refresh (optional) | 1//0dx... |
GOOGLE_DRIVE_MCP_CLIENT_ID |
OAuth client ID (required with refresh token) | 123456789.apps.googleusercontent.com |
GOOGLE_DRIVE_MCP_CLIENT_SECRET |
OAuth client secret (required with refresh token) | GOCSPX-... |
These are standard system environment variables that the application reads but you typically don't need to set:
| Variable | Description | Used For |
|---|---|---|
XDG_CONFIG_HOME |
Linux/Unix config directory standard | Determining default token storage location |
NODE_ENV |
Node.js environment mode | May affect error handling and logging |
| Variable | Description |
|---|---|
GOOGLE_TOKEN_PATH |
Legacy token path - use GOOGLE_DRIVE_MCP_TOKEN_PATH instead |
GOOGLE_CLIENT_SECRET_PATH |
Legacy credentials path - use GOOGLE_DRIVE_OAUTH_CREDENTIALS instead |
MIT - See LICENSE file for details
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Built on Model Context Protocol
- Uses Google APIs Node.js Client
- Inspired by the MCP community