gmcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +183 -0
- package/dist/auth-cli.js +82 -0
- package/dist/index.js +3391 -0
- package/dist/shared/chunk-n2k9eesp.js +169 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# GMCP
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for Google services. Provides Gmail and Google Calendar integration with 19 tools for email management and calendar operations.
|
|
4
|
+
|
|
5
|
+
## Gmail Tools
|
|
6
|
+
|
|
7
|
+
### Email Operations
|
|
8
|
+
|
|
9
|
+
| Tool | Description |
|
|
10
|
+
|------|-------------|
|
|
11
|
+
| `gmcp_gmail_search_emails` | Search emails using Gmail query syntax |
|
|
12
|
+
| `gmcp_gmail_get_email` | Get single email by message ID |
|
|
13
|
+
| `gmcp_gmail_get_thread` | Get entire conversation thread |
|
|
14
|
+
| `gmcp_gmail_list_attachments` | List all attachments on a message |
|
|
15
|
+
| `gmcp_gmail_get_attachment` | Download attachment data by ID |
|
|
16
|
+
| `gmcp_gmail_send_email` | Send email (preview + confirm safety) |
|
|
17
|
+
| `gmcp_gmail_reply` | Reply to email in thread (preview + confirm) |
|
|
18
|
+
| `gmcp_gmail_create_draft` | Create draft message |
|
|
19
|
+
|
|
20
|
+
### Label Management
|
|
21
|
+
|
|
22
|
+
| Tool | Description |
|
|
23
|
+
|------|-------------|
|
|
24
|
+
| `gmcp_gmail_list_labels` | List all Gmail labels (system + custom) |
|
|
25
|
+
| `gmcp_gmail_get_label` | Get label details and message counts |
|
|
26
|
+
| `gmcp_gmail_create_label` | Create custom label with visibility/color settings |
|
|
27
|
+
| `gmcp_gmail_update_label` | Update label name, visibility, or color |
|
|
28
|
+
| `gmcp_gmail_delete_label` | Delete custom label (system labels protected) |
|
|
29
|
+
| `gmcp_gmail_modify_labels` | Add/remove labels on a message |
|
|
30
|
+
| `gmcp_gmail_batch_modify` | Batch label operations on multiple messages |
|
|
31
|
+
|
|
32
|
+
## Calendar Tools
|
|
33
|
+
|
|
34
|
+
| Tool | Description |
|
|
35
|
+
|------|-------------|
|
|
36
|
+
| `gmcp_calendar_list_calendars` | List all calendars for account |
|
|
37
|
+
| `gmcp_calendar_list_events` | List events with filters (time range, query, calendar) |
|
|
38
|
+
| `gmcp_calendar_get_event` | Get single event by ID |
|
|
39
|
+
| `gmcp_calendar_create_event` | Create event (supports recurring events, Google Meet) |
|
|
40
|
+
|
|
41
|
+
## Setup
|
|
42
|
+
|
|
43
|
+
### Prerequisites
|
|
44
|
+
|
|
45
|
+
1. **Google Cloud Project** with Gmail API and Calendar API enabled
|
|
46
|
+
2. **OAuth 2.0 Client ID** (Desktop Application type)
|
|
47
|
+
- Create at [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
|
|
48
|
+
- Download credentials JSON file
|
|
49
|
+
|
|
50
|
+
### Install & Configure
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Install dependencies
|
|
54
|
+
bun install
|
|
55
|
+
|
|
56
|
+
# Copy environment template
|
|
57
|
+
cp .env.example .env
|
|
58
|
+
|
|
59
|
+
# Edit .env with your paths
|
|
60
|
+
# GOOGLE_CREDENTIALS_PATH=/path/to/credentials.json
|
|
61
|
+
# GOOGLE_TOKEN_PATH=/path/to/token.json
|
|
62
|
+
# GOOGLE_SCOPES=gmail.readonly,calendar.readonly
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Authenticate
|
|
66
|
+
|
|
67
|
+
Run the OAuth flow to obtain tokens:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
bun run auth
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Follow the prompts:
|
|
74
|
+
1. Visit the authorization URL in your browser
|
|
75
|
+
2. Authorize the app
|
|
76
|
+
3. Copy the authorization code from the redirected URL
|
|
77
|
+
4. Paste it in the terminal
|
|
78
|
+
|
|
79
|
+
The browser will show "connection refused" after authorization - **this is expected**. Just copy the `code=` parameter from the URL.
|
|
80
|
+
|
|
81
|
+
### Run the Server
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
bun run start
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The server runs via stdio and is ready to accept MCP requests.
|
|
88
|
+
|
|
89
|
+
## Configuration
|
|
90
|
+
|
|
91
|
+
### Environment Variables
|
|
92
|
+
|
|
93
|
+
| Variable | Description |
|
|
94
|
+
|----------|-------------|
|
|
95
|
+
| `GOOGLE_CREDENTIALS_PATH` | Path to OAuth2 credentials JSON from Google Cloud Console |
|
|
96
|
+
| `GOOGLE_TOKEN_PATH` | Path where OAuth2 tokens will be stored |
|
|
97
|
+
| `GOOGLE_SCOPES` | Comma-separated Gmail and Calendar API scopes (short names or full URLs) |
|
|
98
|
+
|
|
99
|
+
### Gmail Scopes
|
|
100
|
+
|
|
101
|
+
| Short Name | Description | Required For |
|
|
102
|
+
|------------|-------------|--------------|
|
|
103
|
+
| `gmail.readonly` | Read-only access | Search, get email, get thread, list/get attachments, list labels, get label |
|
|
104
|
+
| `gmail.modify` | Read, create, update, delete | Modify labels, batch modify |
|
|
105
|
+
| `gmail.labels` | Manage labels | Create label, update label, delete label, modify labels, batch modify |
|
|
106
|
+
| `gmail.send` | Send messages | Send email, reply |
|
|
107
|
+
| `gmail.compose` | Create drafts and send | Send email, reply, create draft |
|
|
108
|
+
|
|
109
|
+
### Calendar Scopes
|
|
110
|
+
|
|
111
|
+
| Short Name | Description | Required For |
|
|
112
|
+
|------------|-------------|--------------|
|
|
113
|
+
| `calendar.readonly` | Read-only calendar access | List calendars, list events, get event |
|
|
114
|
+
| `calendar.events.readonly` | Read-only events access | List events, get event |
|
|
115
|
+
| `calendar.events` | Manage events | Create event, list events, get event |
|
|
116
|
+
| `calendar` | Full calendar access | All calendar tools |
|
|
117
|
+
|
|
118
|
+
### Scope Examples
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# Gmail read-only
|
|
122
|
+
GOOGLE_SCOPES=gmail.readonly
|
|
123
|
+
|
|
124
|
+
# Gmail and Calendar read-only
|
|
125
|
+
GOOGLE_SCOPES=gmail.readonly,calendar.readonly
|
|
126
|
+
|
|
127
|
+
# Gmail read/send + Calendar read/create
|
|
128
|
+
GOOGLE_SCOPES=gmail.readonly,gmail.send,calendar.events
|
|
129
|
+
|
|
130
|
+
# Full access (all tools)
|
|
131
|
+
GOOGLE_SCOPES=gmail.readonly,gmail.modify,gmail.send,gmail.labels,calendar
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Claude Desktop Integration
|
|
135
|
+
|
|
136
|
+
Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"mcpServers": {
|
|
141
|
+
"gmcp": {
|
|
142
|
+
"command": "bun",
|
|
143
|
+
"args": ["run", "/path/to/gmcp/src/index.ts"],
|
|
144
|
+
"env": {
|
|
145
|
+
"GOOGLE_CREDENTIALS_PATH": "/path/to/credentials.json",
|
|
146
|
+
"GOOGLE_TOKEN_PATH": "/path/to/token.json",
|
|
147
|
+
"GOOGLE_SCOPES": "gmail.readonly,gmail.send,gmail.labels,calendar.events"
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Docker
|
|
155
|
+
|
|
156
|
+
Run with Docker:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
docker build -t gmcp-server .
|
|
160
|
+
docker run -i \
|
|
161
|
+
-v /path/to/credentials.json:/app/data/credentials.json:ro \
|
|
162
|
+
-v /path/to/token.json:/app/data/token.json \
|
|
163
|
+
-e GOOGLE_CREDENTIALS_PATH=/app/data/credentials.json \
|
|
164
|
+
-e GOOGLE_TOKEN_PATH=/app/data/token.json \
|
|
165
|
+
-e GOOGLE_SCOPES=gmail.readonly,gmail.labels,gmail.send,calendar.events \
|
|
166
|
+
gmcp-server
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Testing
|
|
170
|
+
|
|
171
|
+
Test with MCP Inspector:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
bunx @modelcontextprotocol/inspector bun run start
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Future Enhancements
|
|
178
|
+
|
|
179
|
+
Potential additions include Google Drive, Google Sheets, and other Google Workspace services.
|
|
180
|
+
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
MIT
|
package/dist/auth-cli.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
createOAuth2Client,
|
|
4
|
+
getAuthUrl,
|
|
5
|
+
getEnvConfig,
|
|
6
|
+
getTokensFromCode,
|
|
7
|
+
loadCredentials,
|
|
8
|
+
saveTokens
|
|
9
|
+
} from "./shared/chunk-n2k9eesp.js";
|
|
10
|
+
|
|
11
|
+
// src/auth-cli.ts
|
|
12
|
+
import { createInterface } from "node:readline";
|
|
13
|
+
function readLine() {
|
|
14
|
+
const rl = createInterface({
|
|
15
|
+
input: process.stdin,
|
|
16
|
+
output: process.stdout
|
|
17
|
+
});
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
rl.on("line", (line) => {
|
|
20
|
+
rl.close();
|
|
21
|
+
resolve(line.trim());
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async function main() {
|
|
26
|
+
console.log(`GMCP Server - OAuth2 Authentication
|
|
27
|
+
`);
|
|
28
|
+
const { credentialsPath, tokenPath, scopes } = getEnvConfig();
|
|
29
|
+
console.log(`Credentials file: ${credentialsPath}`);
|
|
30
|
+
console.log(`Token file: ${tokenPath}`);
|
|
31
|
+
console.log(`Scopes: ${scopes.join(", ")}
|
|
32
|
+
`);
|
|
33
|
+
console.log("Loading OAuth2 credentials...");
|
|
34
|
+
const credentials = await loadCredentials(credentialsPath);
|
|
35
|
+
const oauth2Client = createOAuth2Client(credentials);
|
|
36
|
+
const authUrl = getAuthUrl(oauth2Client, scopes);
|
|
37
|
+
console.log(`
|
|
38
|
+
========================================`);
|
|
39
|
+
console.log("STEP 1: Visit this URL to authorize:");
|
|
40
|
+
console.log("========================================");
|
|
41
|
+
console.log("\x1B[36m%s\x1B[0m", authUrl);
|
|
42
|
+
console.log(`
|
|
43
|
+
========================================`);
|
|
44
|
+
console.log("STEP 2: After authorizing:");
|
|
45
|
+
console.log("========================================");
|
|
46
|
+
console.log('You will be redirected to localhost (which will show "connection refused").');
|
|
47
|
+
console.log("This is EXPECTED! Look at the URL in your browser's address bar.");
|
|
48
|
+
console.log(`
|
|
49
|
+
The URL will look like:`);
|
|
50
|
+
console.log(" http://localhost:PORT/?code=YOUR_CODE_HERE&scope=...");
|
|
51
|
+
console.log(`
|
|
52
|
+
Copy the entire code after "code=" (the long string before "&scope")`);
|
|
53
|
+
console.log(`
|
|
54
|
+
========================================`);
|
|
55
|
+
console.log("STEP 3: Paste the authorization code below:");
|
|
56
|
+
console.log("========================================");
|
|
57
|
+
const code = await readLine();
|
|
58
|
+
if (!code) {
|
|
59
|
+
console.error("Error: No authorization code provided");
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
console.log(`
|
|
63
|
+
Exchanging authorization code for tokens...`);
|
|
64
|
+
try {
|
|
65
|
+
const tokens = await getTokensFromCode(oauth2Client, code);
|
|
66
|
+
await saveTokens(tokenPath, tokens);
|
|
67
|
+
console.log("\x1B[32m%s\x1B[0m", `
|
|
68
|
+
Success! Tokens saved to`, tokenPath);
|
|
69
|
+
console.log(`
|
|
70
|
+
You can now run the MCP server with: npx gmcp`);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error("\x1B[31m%s\x1B[0m", `
|
|
73
|
+
Error exchanging code for tokens:`);
|
|
74
|
+
console.error(error);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
main().catch((error) => {
|
|
79
|
+
console.error("\x1B[31m%s\x1B[0m", "Fatal error:");
|
|
80
|
+
console.error(error);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
});
|