google-calendar-mcp
A production-ready MCP server that lets AI assistants interact with your personal Google Calendar using the Google Calendar API and OAuth 2.0.
README
google-calendar-mcp
A production-ready Model Context Protocol (MCP) server that lets AI assistants interact with your personal Google Calendar using the Google Calendar API and OAuth 2.0.
Connect it to Cursor, Claude Desktop, VS Code, or any MCP client that supports stdio transport. Each user runs a local copy with their own Google credentials.
Security: Never commit
.envor real OAuth tokens. See SECURITY.md.
Features
- 7 MCP tools — list calendars, list / search / create / update / delete events, and free/busy queries
- OAuth 2.0 with refresh tokens — access tokens refresh automatically; you never paste a short-lived access token
- Zod validation on every tool input
- Structured logging to stderr (tool name, duration, API errors)
- Graceful errors — 401, 403, 404, 429, network failures, and expired refresh tokens return readable MCP errors without crashing
- stdio transport — works with local MCP hosts out of the box
Architecture overview
┌─────────────────────┐ stdio (JSON-RPC) ┌──────────────────────────┐
│ MCP Client │ ◄───────────────────────► │ google-calendar-mcp │
│ Cursor / Claude / │ │ McpServer + tools │
│ VS Code │ │ auth.ts → OAuth2 │
└─────────────────────┘ │ calendar.ts → API calls │
└────────────┬─────────────┘
│
▼
┌──────────────────────────┐
│ Google Calendar API v3 │
│ (googleapis + refresh) │
└──────────────────────────┘
- The MCP client spawns this server as a child process.
- Credentials are loaded from
.env(or the clientenvblock). googleapisrefreshes access tokens using your refresh token as needed.- Tools in
src/tools/call shared helpers insrc/calendar.ts(no duplicated API logic).
This is a single-user, local server—not a multi-tenant cloud service.
Screenshots
Place screenshots under
docs/images/after publishing if desired.
| Cursor MCP connected | Example tool result |
|---|---|
![]() |
![]() |
(Image paths are placeholders until you add screenshots.)
Tech stack
| Technology | Role |
|---|---|
| TypeScript | Strict-mode application language |
| Node.js 18+ | Runtime |
| @modelcontextprotocol/sdk | MCP server (McpServer, registerTool, StdioServerTransport) |
| googleapis | Official Google Calendar client |
| zod | Tool input schemas |
| dotenv | Local environment loading |
| tsx | Development runner |
Docker is not provided. This server uses stdio; MCP clients typically start a local Node process. Packaging it in Docker is unnecessary for the supported setup.
Requirements
- Node.js 18 or later
- A Google Cloud project
- Google Calendar API enabled
- OAuth 2.0 client ID and secret
- A refresh token with Calendar access
- An MCP-compatible client (Cursor, Claude Desktop, VS Code, etc.)
Installation
git clone https://github.com/[your-org]/google-calendar-mcp.git
cd google-calendar-mcp
npm install
Copy the environment template:
cp .env.example .env
Fill in your credentials (see Google Cloud OAuth setup below). Never commit .env.
Environment variables
| Variable | Required | Description |
|---|---|---|
GOOGLE_CLIENT_ID |
Yes | OAuth 2.0 client ID from Google Cloud Console |
GOOGLE_CLIENT_SECRET |
Yes | OAuth 2.0 client secret |
GOOGLE_REFRESH_TOKEN |
Yes | Long-lived refresh token from the OAuth consent flow |
DEFAULT_CALENDAR_ID |
No | Default calendar when a tool omits calendarId (default: primary) |
Example .env (placeholders only):
GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-client-secret
GOOGLE_REFRESH_TOKEN=your-refresh-token
DEFAULT_CALENDAR_ID=primary
Google Cloud OAuth setup
Follow these steps if you have never used Google Cloud. Screens and labels change occasionally; use the current Console navigation that matches each step.
1. Create a Google Cloud project
- Open Google Cloud Console.
- Click the project selector at the top → New Project.
- Enter a name (for example
google-calendar-mcp) → Create. - Select the new project.
2. Enable the Google Calendar API
- Go to APIs & Services → Library.
- Search for Google Calendar API.
- Open it → click Enable.
3. Configure the OAuth consent screen
- Go to APIs & Services → OAuth consent screen.
- Choose External (unless you use Google Workspace Internal) → Create.
- Fill in App name, User support email, and Developer contact.
- Save and continue through Scopes / Test users as prompted.
- Under Test users (while the app is in Testing), add the Google account whose calendar you will use.
Important: In Testing mode, refresh tokens may expire after 7 days. For personal long-term use, keep yourself as a test user or publish the app when eligible. Revoking access or resetting the OAuth client also invalidates tokens.
4. Create an OAuth client ID
-
Go to APIs & Services → Credentials.
-
Click Create credentials → OAuth client ID.
-
Application type:
- Web application is easiest with the OAuth Playground (recommended below), or
- Desktop app if you prefer another flow later.
-
Name the client (for example
calendar-mcp-local). -
If using Web application, under Authorized redirect URIs add:
https://developers.google.com/oauthplayground -
Click Create. Copy the Client ID and Client secret into your
.envfile.
5. Required OAuth scope
This server needs:
https://www.googleapis.com/auth/calendar
That scope allows reading and writing calendar data for the authorized account.
6. Obtain a refresh token (OAuth 2.0 Playground)
- Open Google OAuth 2.0 Playground.
- Click the gear icon (top right).
- Check Use your own OAuth credentials.
- Paste your Client ID and Client secret → close the dialog.
- In the left list, expand Calendar API v3 and select
https://www.googleapis.com/auth/calendar
(or paste that scope in the custom scope box). - Click Authorize APIs and sign in with your test user account. Grant the permissions.
- Click Exchange authorization code for tokens.
- Copy the
refresh_tokenvalue (not the access token) into.envasGOOGLE_REFRESH_TOKEN.
If you do not see a refresh token, revoke the app at Google Account permissions and repeat with your own credentials and “offline” access (Playground does this when configured as above).
7. First-time authentication check
From the project root:
npm run build
npm run dev
On success, stderr should include structured logs such as:
OAuth2 client initializedAuthentication validated successfullygoogle-calendar-mcp server connected and ready
Then stop with Ctrl+C. For day-to-day use, configure an MCP client so it starts the server for you (next sections). You do not need to keep a terminal open after the client is configured.
Running locally
Build and start
npm run build
npm start
Development (no build step)
npm run dev
Type-check only
npm run typecheck
The process listens on stdio. Running it alone in a terminal will look idle after startup—that is expected. Use an MCP client or the MCP Inspector:
npx @modelcontextprotocol/inspector node dist/index.js
Configuration
Use absolute paths. Prefer built dist/index.js after npm run build. Secrets can live in .env (loaded by the server) and/or in the client env block.
Cursor
Project file: .cursor/mcp.json (or Cursor global MCP settings). See also examples/mcp-cursor.json.
{
"mcpServers": {
"google-calendar": {
"command": "node",
"args": ["/absolute/path/to/google-calendar-mcp/dist/index.js"],
"env": {
"GOOGLE_CLIENT_ID": "your-client-id.apps.googleusercontent.com",
"GOOGLE_CLIENT_SECRET": "your-client-secret",
"GOOGLE_REFRESH_TOKEN": "your-refresh-token",
"DEFAULT_CALENDAR_ID": "primary"
}
}
}
}
Restart Cursor and confirm the server is connected under Settings → MCP.
Claude Desktop
Config file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"google-calendar": {
"command": "node",
"args": ["/absolute/path/to/google-calendar-mcp/dist/index.js"],
"env": {
"GOOGLE_CLIENT_ID": "your-client-id.apps.googleusercontent.com",
"GOOGLE_CLIENT_SECRET": "your-client-secret",
"GOOGLE_REFRESH_TOKEN": "your-refresh-token",
"DEFAULT_CALENDAR_ID": "primary"
}
}
}
}
VS Code
Add under your MCP / Copilot MCP server settings (exact key may vary by extension):
{
"mcp": {
"servers": {
"google-calendar": {
"command": "node",
"args": ["/absolute/path/to/google-calendar-mcp/dist/index.js"],
"env": {
"GOOGLE_CLIENT_ID": "your-client-id.apps.googleusercontent.com",
"GOOGLE_CLIENT_SECRET": "your-client-secret",
"GOOGLE_REFRESH_TOKEN": "your-refresh-token"
}
}
}
}
}
Available MCP tools
| Tool | Description |
|---|---|
list_calendars |
Returns every calendar available to the authenticated user |
list_events |
Lists events in a time range (optional filters) |
search_events |
Free-text search via Google’s q parameter |
create_event |
Creates an event; returns created event details including id |
update_event |
Partially updates an event (only supplied fields) |
delete_event |
Deletes an event |
free_busy |
Returns busy periods for one or more calendars |
Example prompts
Ask your AI client natural language such as:
- “List my calendars.”
- “What meetings do I have tomorrow?”
- “Search my calendar for dentist.”
- “Create a 1-hour event called Team Sync tomorrow at 10am.”
- “Am I free Friday afternoon?”
See examples/prompts.md for more.
Sample tool request
{
"name": "list_events",
"arguments": {
"timeMin": "2026-07-14T00:00:00Z",
"timeMax": "2026-07-21T00:00:00Z",
"maxResults": 5,
"orderBy": "startTime"
}
}
Sample tool response (illustrative only)
[
{
"id": "abc123example",
"summary": "Team Sync",
"start": { "dateTime": "2026-07-15T10:00:00-07:00" },
"end": { "dateTime": "2026-07-15T11:00:00-07:00" },
"status": "confirmed",
"htmlLink": "https://www.google.com/calendar/event?eid=example"
}
]
More samples: examples/sample-responses.md.
Project structure
google-calendar-mcp/
├── src/
│ ├── index.ts # Entry — stdio transport
│ ├── server.ts # McpServer factory and tool registration
│ ├── auth.ts # OAuth2 client and token refresh
│ ├── calendar.ts # Google Calendar API wrapper
│ ├── types.ts # Shared TypeScript types
│ ├── utils.ts # Logging, error handling, helpers
│ └── tools/
│ ├── listCalendars.ts
│ ├── listEvents.ts
│ ├── searchEvents.ts
│ ├── createEvent.ts
│ ├── updateEvent.ts
│ ├── deleteEvent.ts
│ └── freeBusy.ts
├── examples/ # Sample configs and prompts (no secrets)
├── .env.example
├── package.json
├── tsconfig.json
├── LICENSE
├── CONTRIBUTING.md
├── SECURITY.md
├── CODE_OF_CONDUCT.md
├── CHANGELOG.md
└── README.md
Development workflow
npm install
cp .env.example .env # add your credentials
npm run typecheck
npm run build
npm run dev # or connect via MCP Inspector / Cursor
Contributions welcome—see CONTRIBUTING.md.
Troubleshooting
| Problem | What to try |
|---|---|
| Missing environment variables | Copy .env.example → .env and set all three Google variables |
| Authentication failed (401) / invalid refresh token | Re-run OAuth Playground; ensure Client ID matches the token; revoke and re-authorize if needed |
| Permission denied (403) | Enable Google Calendar API; confirm scope includes calendar; ensure you are a consent screen test user |
| Rate limit (429) | Wait and retry; lower maxResults |
redirect_uri_mismatch in Playground |
Add https://developers.google.com/oauthplayground to authorized redirect URIs |
| MCP client cannot connect | Use absolute paths; run npm run build first; ensure Node 18+ is on PATH |
| Server seems frozen after start | Normal for stdio—clients must spawn and speak the protocol |
| Refresh token stops working after ~7 days | App is in Testing mode—see OAuth consent screen notes above |
Logs are written as JSON lines to stderr. Do not log secrets.
FAQ
Do I need to keep a terminal open for Cursor?
No. Once MCP is configured, Cursor starts and stops the server automatically.
Is this multi-user?
No. One process uses one set of credentials and one Google account.
Can I publish my .env?
Never. Treat client secret and refresh token like passwords.
Can I use a service account?
This project is built for user OAuth with a refresh token, not service accounts.
Why no Docker?
MCP stdio clients spawn a local command. Running Node directly is the supported path.
Contributing
See CONTRIBUTING.md and CODE_OF_CONDUCT.md.
License
This project is licensed under the MIT License.
Acknowledgements
- Model Context Protocol and the TypeScript SDK
- Google Calendar API and the googleapis Node.js client
- Contributor Covenant for the Code of Conduct template
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

