Motivation
As a daily Cursor IDE user, I'm constantly looking for ways to enhance my development workflow. I love how Cursor's AI capabilities help me code faster, but I wanted to take it further by integrating my personal productivity tools directly into the IDE. Google Tasks is my go-to task management system, and building an MCP server to connect it with Cursor seemed like the perfect project to tackle.
This project gave me a chance to dive deeper into MCP server development while creating something I'll actually use every day. Plus, working with the Google Tasks API provided great practice with OAuth2 authentication and RESTful service integration.
Implementation
Let's walk through building a production-ready MCP server for Google Tasks integration. We'll create a TypeScript project that handles authentication, makes API calls, and exposes task management capabilities to Cursor IDE.
Project Structure
First, let's set up our project structure:
mcp-server/
├── src/
│ ├── server.ts # Main MCP server implementation
│ ├── main.ts # Entry point
│ └── types.ts # Type definitions
├── package.json
├── tsconfig.json
└── .env
Installing Dependencies
Create a new project and install the required dependencies:
npm init -y
npm install @cursor/mcp-server axios dotenv zod google-auth-library
npm install -D typescript @types/node
Our package.json should include:
{
"name": "google-tasks-mcp",
"version": "1.0.0",
"main": "dist/main.js",
"scripts": {
"build": "tsc",
"start": "node dist/main.js"
},
"dependencies": {
"@cursor/mcp-server": "^1.0.0",
"axios": "^1.6.0",
"dotenv": "^16.3.1",
"zod": "^3.22.4",
"google-auth-library": "^9.0.0"
}
}
Environment Configuration
Create a .env file to store API credentials:
GOOGLE_CLIENT_ID=your_client_id
GOOGLE_CLIENT_SECRET=your_client_secret
GOOGLE_REFRESH_TOKEN=your_refresh_token
Server Implementation
Let's build our server.ts file step by step:
import { MCPServer } from '@cursor/mcp-server';
import { z } from 'zod';
import { OAuth2Client } from 'google-auth-library';
import axios from 'axios';
import dotenv from 'dotenv';
// Load environment variables
dotenv.config();
// Validate environment variables
const envSchema = z.object({
GOOGLE_CLIENT_ID: z.string(),
GOOGLE_CLIENT_SECRET: z.string(),
GOOGLE_REFRESH_TOKEN: z.string(),
});
const env = envSchema.parse(process.env);
// Create OAuth2 client
const oauth2Client = new OAuth2Client(
env.GOOGLE_CLIENT_ID,
env.GOOGLE_CLIENT_SECRET,
'urn:ietf:wg:oauth:2.0:oob'
);
oauth2Client.setCredentials({
refresh_token: env.GOOGLE_REFRESH_TOKEN
});
// Create axios instance with auth interceptor
const client = axios.create({
baseURL: 'https://tasks.googleapis.com/tasks/v1'
});
client.interceptors.request.use(async (config) => {
const token = await oauth2Client.getAccessToken();
config.headers.Authorization = `Bearer ${token.token}`;
return config;
});
// Create MCP server instance
const mcpServer = new MCPServer();
// Add tools
mcpServer.tool({
name: 'list_tasks',
description: 'List all tasks in a specified task list',
parameters: z.object({
taskListId: z.string().describe('The ID of the task list to fetch tasks from')
}),
handler: async ({ taskListId }) => {
const response = await client.get(`/lists/${taskListId}/tasks`);
return response.data.items;
}
});
mcpServer.tool({
name: 'create_task',
description: 'Create a new task in a specified task list',
parameters: z.object({
taskListId: z.string().describe('The ID of the task list'),
title: z.string().describe('The title of the task'),
notes: z.string().optional().describe('Optional notes for the task'),
due: z.string().optional().describe('Due date in RFC3339 format')
}),
handler: async ({ taskListId, title, notes, due }) => {
const response = await client.post(`/lists/${taskListId}/tasks`, {
title,
notes,
due
});
return response.data;
}
});
export default mcpServer;
Entry Point
Create main.ts to start the server:
import mcpServer from './server';
const port = process.env.PORT || 3000;
mcpServer.listen(port, () => {
console.log(`Google Tasks MCP server listening on port ${port}`);
});
Usage
Let's go through how to set up and use the Google Tasks MCP server with Cursor IDE.
Installation
Install the package globally:
npm install -g google-tasks-mcp
Configuration
Add the following entry to your Cursor IDE's mcp.json file:
{
"servers": {
"google-tasks": {
"command": "google-tasks-mcp",
"tools": [
"list_tasks",
"create_task"
]
}
}
}
Example Prompts
Here are some example prompts you can use in Cursor IDE:
- Listing tasks:
Show me all tasks in my main task list
Response:
Here are your tasks from the main list:
- Complete MCP server documentation (due: tomorrow)
- Review pull requests (due: today)
- Update deployment scripts (due: next week)
- Creating a task:
Create a new task titled "Implement error handling" due tomorrow
Response:
Created new task:
Title: Implement error handling
Due: 2024-01-10T23:59:59Z
Status: needsAction
- Task management:
Add a task to review the API documentation with notes about checking rate limits
Response:
Created new task:
Title: Review API documentation
Notes: Check and document rate limits
Status: needsAction
How It Works
Here's a sequence diagram showing how the Google Tasks MCP server integrates with Cursor IDE:
Rendering diagram...
The diagram shows how user prompts in Cursor IDE are transformed into API calls through the MCP server, which handles authentication and data transformation before returning results back to the user.