google-workspace-mcp 2.0.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/LICENSE +7 -0
- package/README.md +765 -0
- package/dist/accounts.d.ts +85 -0
- package/dist/accounts.d.ts.map +1 -0
- package/dist/accounts.js +520 -0
- package/dist/accounts.js.map +1 -0
- package/dist/auth.d.ts +4 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +206 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +426 -0
- package/dist/cli.js.map +1 -0
- package/dist/errorHelpers.d.ts +40 -0
- package/dist/errorHelpers.d.ts.map +1 -0
- package/dist/errorHelpers.js +52 -0
- package/dist/errorHelpers.js.map +1 -0
- package/dist/googleDocsApiHelpers.d.ts +118 -0
- package/dist/googleDocsApiHelpers.d.ts.map +1 -0
- package/dist/googleDocsApiHelpers.js +850 -0
- package/dist/googleDocsApiHelpers.js.map +1 -0
- package/dist/googleSheetsApiHelpers.d.ts +75 -0
- package/dist/googleSheetsApiHelpers.d.ts.map +1 -0
- package/dist/googleSheetsApiHelpers.js +376 -0
- package/dist/googleSheetsApiHelpers.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +119 -0
- package/dist/server.js.map +1 -0
- package/dist/serverWrapper.d.ts +21 -0
- package/dist/serverWrapper.d.ts.map +1 -0
- package/dist/serverWrapper.js +74 -0
- package/dist/serverWrapper.js.map +1 -0
- package/dist/tools/accounts.tools.d.ts +3 -0
- package/dist/tools/accounts.tools.d.ts.map +1 -0
- package/dist/tools/accounts.tools.js +154 -0
- package/dist/tools/accounts.tools.js.map +1 -0
- package/dist/tools/calendar.tools.d.ts +3 -0
- package/dist/tools/calendar.tools.d.ts.map +1 -0
- package/dist/tools/calendar.tools.js +487 -0
- package/dist/tools/calendar.tools.js.map +1 -0
- package/dist/tools/docs.tools.d.ts +3 -0
- package/dist/tools/docs.tools.d.ts.map +1 -0
- package/dist/tools/docs.tools.js +1766 -0
- package/dist/tools/docs.tools.js.map +1 -0
- package/dist/tools/drive.tools.d.ts +3 -0
- package/dist/tools/drive.tools.d.ts.map +1 -0
- package/dist/tools/drive.tools.js +1001 -0
- package/dist/tools/drive.tools.js.map +1 -0
- package/dist/tools/forms.tools.d.ts +3 -0
- package/dist/tools/forms.tools.d.ts.map +1 -0
- package/dist/tools/forms.tools.js +370 -0
- package/dist/tools/forms.tools.js.map +1 -0
- package/dist/tools/gmail.tools.d.ts +3 -0
- package/dist/tools/gmail.tools.d.ts.map +1 -0
- package/dist/tools/gmail.tools.js +520 -0
- package/dist/tools/gmail.tools.js.map +1 -0
- package/dist/tools/sheets.tools.d.ts +3 -0
- package/dist/tools/sheets.tools.d.ts.map +1 -0
- package/dist/tools/sheets.tools.js +521 -0
- package/dist/tools/sheets.tools.js.map +1 -0
- package/dist/tools/slides.tools.d.ts +3 -0
- package/dist/tools/slides.tools.d.ts.map +1 -0
- package/dist/tools/slides.tools.js +323 -0
- package/dist/tools/slides.tools.js.map +1 -0
- package/dist/types.d.ts +507 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +185 -0
- package/dist/types.js.map +1 -0
- package/dist/urlHelpers.d.ts +60 -0
- package/dist/urlHelpers.d.ts.map +1 -0
- package/dist/urlHelpers.js +101 -0
- package/dist/urlHelpers.js.map +1 -0
- package/package.json +77 -0
package/dist/auth.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// src/auth.ts
|
|
2
|
+
import { google } from 'googleapis';
|
|
3
|
+
import { JWT } from 'google-auth-library'; // ADDED: Import for Service Account client
|
|
4
|
+
import * as fs from 'fs/promises';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import * as readline from 'readline/promises';
|
|
7
|
+
import * as http from 'http';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
// --- Calculate paths relative to this script file (ESM way) ---
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
const projectRootDir = path.resolve(__dirname, '..');
|
|
13
|
+
const TOKEN_PATH = path.join(projectRootDir, 'token.json');
|
|
14
|
+
const CREDENTIALS_PATH = path.join(projectRootDir, 'credentials.json');
|
|
15
|
+
// --- End of path calculation ---
|
|
16
|
+
const SCOPES = [
|
|
17
|
+
'https://www.googleapis.com/auth/documents',
|
|
18
|
+
'https://www.googleapis.com/auth/drive', // Full Drive access for listing, searching, and document discovery
|
|
19
|
+
'https://www.googleapis.com/auth/spreadsheets', // Google Sheets API access
|
|
20
|
+
];
|
|
21
|
+
// --- NEW FUNCTION: Handles Service Account Authentication ---
|
|
22
|
+
// This entire function is new. It is called only when the
|
|
23
|
+
// SERVICE_ACCOUNT_PATH environment variable is set.
|
|
24
|
+
// Supports domain-wide delegation via GOOGLE_IMPERSONATE_USER env var.
|
|
25
|
+
async function authorizeWithServiceAccount() {
|
|
26
|
+
const serviceAccountPath = process.env.SERVICE_ACCOUNT_PATH;
|
|
27
|
+
if (!serviceAccountPath) {
|
|
28
|
+
throw new Error('SERVICE_ACCOUNT_PATH environment variable is required');
|
|
29
|
+
}
|
|
30
|
+
const impersonateUser = process.env.GOOGLE_IMPERSONATE_USER; // Optional: email of user to impersonate
|
|
31
|
+
try {
|
|
32
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- serviceAccountPath from environment variable, admin-controlled
|
|
33
|
+
const keyFileContent = await fs.readFile(serviceAccountPath, 'utf8');
|
|
34
|
+
const serviceAccountKey = JSON.parse(keyFileContent);
|
|
35
|
+
const auth = new JWT({
|
|
36
|
+
email: serviceAccountKey.client_email,
|
|
37
|
+
key: serviceAccountKey.private_key,
|
|
38
|
+
scopes: SCOPES,
|
|
39
|
+
subject: impersonateUser, // Enables domain-wide delegation when set
|
|
40
|
+
});
|
|
41
|
+
await auth.authorize();
|
|
42
|
+
if (impersonateUser) {
|
|
43
|
+
console.error(`Service Account authentication successful, impersonating: ${impersonateUser}`);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
console.error('Service Account authentication successful!');
|
|
47
|
+
}
|
|
48
|
+
return auth;
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
const isNodeError = (e) => e instanceof Error && 'code' in e;
|
|
52
|
+
if (isNodeError(error) && error.code === 'ENOENT') {
|
|
53
|
+
console.error(`FATAL: Service account key file not found at path: ${serviceAccountPath}`);
|
|
54
|
+
throw new Error('Service account key file not found. Please check the path in SERVICE_ACCOUNT_PATH.');
|
|
55
|
+
}
|
|
56
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
57
|
+
console.error('FATAL: Error loading or authorizing the service account key:', message);
|
|
58
|
+
throw new Error('Failed to authorize using the service account. Ensure the key file is valid and the path is correct.');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// --- END OF NEW FUNCTION---
|
|
62
|
+
async function loadSavedCredentialsIfExist() {
|
|
63
|
+
try {
|
|
64
|
+
const content = await fs.readFile(TOKEN_PATH);
|
|
65
|
+
const credentials = JSON.parse(content.toString());
|
|
66
|
+
const { client_secret, client_id, redirect_uris } = await loadClientSecrets();
|
|
67
|
+
const client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]);
|
|
68
|
+
client.setCredentials(credentials);
|
|
69
|
+
return client;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function loadClientSecrets() {
|
|
76
|
+
const content = await fs.readFile(CREDENTIALS_PATH);
|
|
77
|
+
const keys = JSON.parse(content.toString());
|
|
78
|
+
const key = keys.installed ?? keys.web;
|
|
79
|
+
if (!key)
|
|
80
|
+
throw new Error('Could not find client secrets in credentials.json.');
|
|
81
|
+
return {
|
|
82
|
+
client_id: key.client_id,
|
|
83
|
+
client_secret: key.client_secret,
|
|
84
|
+
redirect_uris: key.redirect_uris ?? ['http://localhost:3000/'], // Default for web clients
|
|
85
|
+
client_type: keys.web ? 'web' : 'installed',
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async function saveCredentials(client) {
|
|
89
|
+
const { client_secret, client_id } = await loadClientSecrets();
|
|
90
|
+
const payload = JSON.stringify({
|
|
91
|
+
type: 'authorized_user',
|
|
92
|
+
client_id: client_id,
|
|
93
|
+
client_secret: client_secret,
|
|
94
|
+
refresh_token: client.credentials.refresh_token,
|
|
95
|
+
});
|
|
96
|
+
await fs.writeFile(TOKEN_PATH, payload);
|
|
97
|
+
console.error('Token stored to', TOKEN_PATH);
|
|
98
|
+
}
|
|
99
|
+
async function authenticate() {
|
|
100
|
+
const { client_secret, client_id, redirect_uris, client_type } = await loadClientSecrets();
|
|
101
|
+
// Use localhost redirect for desktop apps (OOB flow is deprecated)
|
|
102
|
+
const redirectUri = client_type === 'web' ? redirect_uris[0] : 'http://localhost:3000';
|
|
103
|
+
console.error(`DEBUG: Using redirect URI: ${redirectUri}`);
|
|
104
|
+
console.error(`DEBUG: Client type: ${client_type}`);
|
|
105
|
+
const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirectUri);
|
|
106
|
+
const authorizeUrl = oAuth2Client.generateAuthUrl({
|
|
107
|
+
access_type: 'offline',
|
|
108
|
+
scope: SCOPES.join(' '),
|
|
109
|
+
});
|
|
110
|
+
console.error('DEBUG: Generated auth URL:', authorizeUrl);
|
|
111
|
+
console.error('Authorize this app by visiting this url:', authorizeUrl);
|
|
112
|
+
// For desktop apps, start a local server to receive the OAuth callback
|
|
113
|
+
if (client_type === 'installed') {
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
const server = http.createServer((req, res) => {
|
|
116
|
+
void (async () => {
|
|
117
|
+
try {
|
|
118
|
+
const url = new URL(req.url || '', 'http://localhost:3000');
|
|
119
|
+
const code = url.searchParams.get('code');
|
|
120
|
+
if (code) {
|
|
121
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
122
|
+
res.end('<html><body><h1>Authentication successful!</h1><p>You can close this window.</p></body></html>');
|
|
123
|
+
server.close();
|
|
124
|
+
const { tokens } = await oAuth2Client.getToken(code);
|
|
125
|
+
oAuth2Client.setCredentials(tokens);
|
|
126
|
+
if (tokens.refresh_token) {
|
|
127
|
+
await saveCredentials(oAuth2Client);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
console.error('Did not receive refresh token. Token might expire.');
|
|
131
|
+
}
|
|
132
|
+
console.error('Authentication successful!');
|
|
133
|
+
resolve(oAuth2Client);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
137
|
+
res.end('<html><body><h1>Error: No code received</h1></body></html>');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
console.error('Error retrieving access token', err);
|
|
142
|
+
res.writeHead(500, { 'Content-Type': 'text/html' });
|
|
143
|
+
res.end('<html><body><h1>Authentication failed</h1></body></html>');
|
|
144
|
+
server.close();
|
|
145
|
+
reject(new Error('Authentication failed'));
|
|
146
|
+
}
|
|
147
|
+
})();
|
|
148
|
+
});
|
|
149
|
+
server.listen(3000, () => {
|
|
150
|
+
console.error('Local server started on http://localhost:3000');
|
|
151
|
+
console.error('Waiting for OAuth callback...');
|
|
152
|
+
});
|
|
153
|
+
server.on('error', (err) => {
|
|
154
|
+
console.error('Server error:', err);
|
|
155
|
+
reject(err);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// For web clients, use readline to get the code manually
|
|
161
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
162
|
+
const code = await rl.question('Enter the code from that page here: ');
|
|
163
|
+
rl.close();
|
|
164
|
+
try {
|
|
165
|
+
const { tokens } = await oAuth2Client.getToken(code);
|
|
166
|
+
oAuth2Client.setCredentials(tokens);
|
|
167
|
+
if (tokens.refresh_token) {
|
|
168
|
+
await saveCredentials(oAuth2Client);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
console.error('Did not receive refresh token. Token might expire.');
|
|
172
|
+
}
|
|
173
|
+
console.error('Authentication successful!');
|
|
174
|
+
return oAuth2Client;
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
console.error('Error retrieving access token', err);
|
|
178
|
+
throw new Error('Authentication failed');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// --- MODIFIED: The Main Exported Function ---
|
|
183
|
+
// This function now acts as a router. It checks for the environment
|
|
184
|
+
// variable and decides which authentication method to use.
|
|
185
|
+
export async function authorize() {
|
|
186
|
+
// Check if the Service Account environment variable is set.
|
|
187
|
+
if (process.env.SERVICE_ACCOUNT_PATH) {
|
|
188
|
+
console.error('Service account path detected. Attempting service account authentication...');
|
|
189
|
+
return authorizeWithServiceAccount();
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
// If not, execute the original OAuth 2.0 flow exactly as it was.
|
|
193
|
+
console.error('No service account path detected. Falling back to standard OAuth 2.0 flow...');
|
|
194
|
+
let client = await loadSavedCredentialsIfExist();
|
|
195
|
+
if (client) {
|
|
196
|
+
// Optional: Add token refresh logic here if needed, though library often handles it.
|
|
197
|
+
console.error('Using saved credentials.');
|
|
198
|
+
return client;
|
|
199
|
+
}
|
|
200
|
+
console.error('Starting authentication flow...');
|
|
201
|
+
client = await authenticate();
|
|
202
|
+
return client;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// --- END OF MODIFIED: The Main Exported Function ---
|
|
206
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,cAAc;AACd,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC,CAAC,2CAA2C;AACtF,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAGpC,iEAAiE;AACjE,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAC3C,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAErD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;AAC3D,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;AACvE,kCAAkC;AAElC,MAAM,MAAM,GAAG;IACb,2CAA2C;IAC3C,uCAAuC,EAAE,mEAAmE;IAC5G,8CAA8C,EAAE,2BAA2B;CAC5E,CAAC;AAEF,+DAA+D;AAC/D,0DAA0D;AAC1D,oDAAoD;AACpD,uEAAuE;AACvE,KAAK,UAAU,2BAA2B;IACxC,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IAC5D,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,yCAAyC;IACtG,IAAI,CAAC;QACH,qIAAqI;QACrI,MAAM,cAAc,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;QACrE,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAsB,CAAC;QAE1E,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC;YACnB,KAAK,EAAE,iBAAiB,CAAC,YAAY;YACrC,GAAG,EAAE,iBAAiB,CAAC,WAAW;YAClC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,eAAe,EAAE,0CAA0C;SACrE,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACvB,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,6DAA6D,eAAe,EAAE,CAAC,CAAC;QAChG,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,WAAW,GAAG,CAAC,CAAU,EAA8B,EAAE,CAC7D,CAAC,YAAY,KAAK,IAAI,MAAM,IAAI,CAAC,CAAC;QACpC,IAAI,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAClD,OAAO,CAAC,KAAK,CAAC,sDAAsD,kBAAkB,EAAE,CAAC,CAAC;YAC1F,MAAM,IAAI,KAAK,CACb,oFAAoF,CACrF,CAAC;QACJ,CAAC;QACD,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO,CAAC,KAAK,CAAC,8DAA8D,EAAE,OAAO,CAAC,CAAC;QACvF,MAAM,IAAI,KAAK,CACb,sGAAsG,CACvG,CAAC;IACJ,CAAC;AACH,CAAC;AACD,6BAA6B;AAE7B,KAAK,UAAU,2BAA2B;IACxC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAgB,CAAC;QAClE,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,MAAM,iBAAiB,EAAE,CAAC;QAC9E,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QAClF,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;QACnC,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AASD,KAAK,UAAU,iBAAiB;IAC9B,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAyB,CAAC;IACpE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC;IACvC,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IAChF,OAAO;QACL,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,CAAC,wBAAwB,CAAC,EAAE,0BAA0B;QAC1F,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW;KAC5C,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,MAAoB;IACjD,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;QAC7B,IAAI,EAAE,iBAAiB;QACvB,SAAS,EAAE,SAAS;QACpB,aAAa,EAAE,aAAa;QAC5B,aAAa,EAAE,MAAM,CAAC,WAAW,CAAC,aAAa;KAChD,CAAC,CAAC;IACH,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACxC,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAC;AAC/C,CAAC;AAED,KAAK,UAAU,YAAY;IACzB,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAC3F,mEAAmE;IACnE,MAAM,WAAW,GAAG,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC;IACvF,OAAO,CAAC,KAAK,CAAC,8BAA8B,WAAW,EAAE,CAAC,CAAC;IAC3D,OAAO,CAAC,KAAK,CAAC,uBAAuB,WAAW,EAAE,CAAC,CAAC;IACpD,MAAM,YAAY,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC;IAEnF,MAAM,YAAY,GAAG,YAAY,CAAC,eAAe,CAAC;QAChD,WAAW,EAAE,SAAS;QACtB,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;KACxB,CAAC,CAAC;IAEH,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,YAAY,CAAC,CAAC;IAC1D,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,YAAY,CAAC,CAAC;IAExE,uEAAuE;IACvE,IAAI,WAAW,KAAK,WAAW,EAAE,CAAC;QAChC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;gBAC5C,KAAK,CAAC,KAAK,IAAI,EAAE;oBACf,IAAI,CAAC;wBACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,EAAE,uBAAuB,CAAC,CAAC;wBAC5D,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;wBAE1C,IAAI,IAAI,EAAE,CAAC;4BACT,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;4BACpD,GAAG,CAAC,GAAG,CACL,gGAAgG,CACjG,CAAC;4BAEF,MAAM,CAAC,KAAK,EAAE,CAAC;4BAEf,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;4BACrD,YAAY,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;4BACpC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;gCACzB,MAAM,eAAe,CAAC,YAAY,CAAC,CAAC;4BACtC,CAAC;iCAAM,CAAC;gCACN,OAAO,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;4BACtE,CAAC;4BACD,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;4BAC5C,OAAO,CAAC,YAAY,CAAC,CAAC;wBACxB,CAAC;6BAAM,CAAC;4BACN,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;4BACpD,GAAG,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAC;wBACxE,CAAC;oBACH,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAC;wBACpD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;wBACpD,GAAG,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC;wBACpE,MAAM,CAAC,KAAK,EAAE,CAAC;wBACf,MAAM,CAAC,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC;oBAC7C,CAAC;gBACH,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;gBACvB,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;gBAC/D,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;YACjD,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACzB,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;gBACpC,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,yDAAyD;QACzD,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACtF,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC,CAAC;QACvE,EAAE,CAAC,KAAK,EAAE,CAAC;QAEX,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACrD,YAAY,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YACpC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;gBACzB,MAAM,eAAe,CAAC,YAAY,CAAC,CAAC;YACtC,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;YACtE,CAAC;YACD,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAC5C,OAAO,YAAY,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;AACH,CAAC;AAED,+CAA+C;AAC/C,oEAAoE;AACpE,2DAA2D;AAC3D,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,4DAA4D;IAC5D,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC;QACrC,OAAO,CAAC,KAAK,CAAC,6EAA6E,CAAC,CAAC;QAC7F,OAAO,2BAA2B,EAAE,CAAC;IACvC,CAAC;SAAM,CAAC;QACN,iEAAiE;QACjE,OAAO,CAAC,KAAK,CAAC,8EAA8E,CAAC,CAAC;QAC9F,IAAI,MAAM,GAAG,MAAM,2BAA2B,EAAE,CAAC;QACjD,IAAI,MAAM,EAAE,CAAC;YACX,qFAAqF;YACrF,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;YAC1C,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACjD,MAAM,GAAG,MAAM,YAAY,EAAE,CAAC;QAC9B,OAAO,MAAM,CAAC;IAChB,CAAC;AACH,CAAC;AACD,sDAAsD"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// src/cli.ts - CLI entrypoint for Google Workspace MCP Server
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import * as fs from 'fs/promises';
|
|
5
|
+
import { exec } from 'child_process';
|
|
6
|
+
import { initializeAccounts, listAccounts, completeAddAccount, removeAccount, getConfigDir, getCredentialsPath, getAccountClients, } from './accounts.js';
|
|
7
|
+
/** Type guard for errors with a message property */
|
|
8
|
+
function isErrorWithMessage(error) {
|
|
9
|
+
return (typeof error === 'object' &&
|
|
10
|
+
error !== null &&
|
|
11
|
+
'message' in error &&
|
|
12
|
+
typeof error.message === 'string');
|
|
13
|
+
}
|
|
14
|
+
/** Type guard for Google API errors with a code property */
|
|
15
|
+
function isGoogleApiError(error) {
|
|
16
|
+
return (isErrorWithMessage(error) &&
|
|
17
|
+
'code' in error &&
|
|
18
|
+
typeof error.code === 'number');
|
|
19
|
+
}
|
|
20
|
+
/** Get error message from unknown error */
|
|
21
|
+
function getErrorMessage(error) {
|
|
22
|
+
if (isErrorWithMessage(error)) {
|
|
23
|
+
return error.message;
|
|
24
|
+
}
|
|
25
|
+
return String(error);
|
|
26
|
+
}
|
|
27
|
+
// Helper to open URL in browser (cross-platform)
|
|
28
|
+
function openBrowser(url) {
|
|
29
|
+
const platform = process.platform;
|
|
30
|
+
let command;
|
|
31
|
+
if (platform === 'darwin') {
|
|
32
|
+
command = `open "${url}"`;
|
|
33
|
+
}
|
|
34
|
+
else if (platform === 'win32') {
|
|
35
|
+
command = `start "" "${url}"`;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
command = `xdg-open "${url}"`;
|
|
39
|
+
}
|
|
40
|
+
// eslint-disable-next-line security/detect-child-process -- command is constructed from known safe platform-specific openers with URL-encoded input
|
|
41
|
+
exec(command, (error) => {
|
|
42
|
+
if (error) {
|
|
43
|
+
console.error('Could not open browser automatically. Please open the URL manually.');
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const program = new Command();
|
|
48
|
+
// Version from package.json
|
|
49
|
+
const packageJsonPath = new URL('../package.json', import.meta.url);
|
|
50
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- packageJsonPath is a known safe path relative to this file
|
|
51
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
|
52
|
+
program
|
|
53
|
+
.name('google-workspace-mcp')
|
|
54
|
+
.description('Google Workspace MCP Server - Manage Google Docs, Sheets, Drive, Gmail, Calendar, Slides, and Forms')
|
|
55
|
+
.version(packageJson.version);
|
|
56
|
+
// === MCP Server Command ===
|
|
57
|
+
program
|
|
58
|
+
.command('serve')
|
|
59
|
+
.alias('mcp')
|
|
60
|
+
.description('Start the MCP server (for use with Claude Desktop, VS Code, etc.)')
|
|
61
|
+
.option('--read-only', 'Run in read-only mode (block all write operations)')
|
|
62
|
+
.action(async (options) => {
|
|
63
|
+
// Set env var for server.ts to pick up
|
|
64
|
+
if (options.readOnly) {
|
|
65
|
+
process.env.GOOGLE_MCP_READ_ONLY = 'true';
|
|
66
|
+
}
|
|
67
|
+
// Dynamically import and start the server
|
|
68
|
+
await import('./server.js');
|
|
69
|
+
});
|
|
70
|
+
// === Setup Command ===
|
|
71
|
+
program
|
|
72
|
+
.command('setup')
|
|
73
|
+
.description('Interactive setup wizard for configuring the MCP server')
|
|
74
|
+
.action(async () => {
|
|
75
|
+
console.log('\nš Google Workspace MCP Server Setup\n');
|
|
76
|
+
console.log('This wizard will help you set up the MCP server.\n');
|
|
77
|
+
const configDir = getConfigDir();
|
|
78
|
+
const credPath = getCredentialsPath();
|
|
79
|
+
console.log('š Configuration directory:', configDir);
|
|
80
|
+
console.log('š Credentials file path:', credPath);
|
|
81
|
+
console.log('');
|
|
82
|
+
// Check if credentials exist
|
|
83
|
+
try {
|
|
84
|
+
await fs.access(credPath);
|
|
85
|
+
console.log('ā
Credentials file found at', credPath);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
console.log('ā Credentials file NOT found at', credPath);
|
|
89
|
+
console.log('');
|
|
90
|
+
console.log('To set up credentials:');
|
|
91
|
+
console.log('1. Go to https://console.cloud.google.com/');
|
|
92
|
+
console.log('2. Create a new project (or select an existing one)');
|
|
93
|
+
console.log('3. Enable the following APIs:');
|
|
94
|
+
console.log(' - Google Docs API');
|
|
95
|
+
console.log(' - Google Drive API');
|
|
96
|
+
console.log(' - Google Sheets API');
|
|
97
|
+
console.log(' - Gmail API');
|
|
98
|
+
console.log(' - Google Calendar API');
|
|
99
|
+
console.log(' - Google Slides API');
|
|
100
|
+
console.log(' - Google Forms API');
|
|
101
|
+
console.log('4. Create OAuth 2.0 credentials (Desktop application)');
|
|
102
|
+
console.log('5. Download the credentials JSON file');
|
|
103
|
+
console.log(`6. Copy it to: ${credPath}`);
|
|
104
|
+
console.log('');
|
|
105
|
+
console.log('After setting up credentials, run this command again or use:');
|
|
106
|
+
console.log(' google-workspace-mcp accounts add <account-name>');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// Initialize and check accounts
|
|
110
|
+
await initializeAccounts();
|
|
111
|
+
const accounts = await listAccounts();
|
|
112
|
+
if (accounts.length === 0) {
|
|
113
|
+
console.log('');
|
|
114
|
+
console.log('No accounts configured yet.');
|
|
115
|
+
console.log('');
|
|
116
|
+
console.log('To add an account, run:');
|
|
117
|
+
console.log(' google-workspace-mcp accounts add <account-name>');
|
|
118
|
+
console.log('');
|
|
119
|
+
console.log('Example:');
|
|
120
|
+
console.log(' google-workspace-mcp accounts add personal');
|
|
121
|
+
console.log(' google-workspace-mcp accounts add work');
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.log('');
|
|
125
|
+
console.log(`ā
Found ${accounts.length} configured account(s):`);
|
|
126
|
+
accounts.forEach((acc, i) => {
|
|
127
|
+
console.log(` ${i + 1}. ${acc.name}${acc.email ? ` (${acc.email})` : ''}`);
|
|
128
|
+
});
|
|
129
|
+
console.log('');
|
|
130
|
+
console.log('Your MCP server is ready to use!');
|
|
131
|
+
console.log('');
|
|
132
|
+
console.log('To start the server:');
|
|
133
|
+
console.log(' google-workspace-mcp serve');
|
|
134
|
+
}
|
|
135
|
+
console.log('');
|
|
136
|
+
console.log('š For more information, see the README.md');
|
|
137
|
+
});
|
|
138
|
+
// === Accounts Commands ===
|
|
139
|
+
const accountsCmd = program.command('accounts').description('Manage Google account authentication');
|
|
140
|
+
accountsCmd
|
|
141
|
+
.command('list')
|
|
142
|
+
.description('List all configured Google accounts')
|
|
143
|
+
.action(async () => {
|
|
144
|
+
await initializeAccounts();
|
|
145
|
+
const accounts = await listAccounts();
|
|
146
|
+
if (accounts.length === 0) {
|
|
147
|
+
console.log('No accounts configured.');
|
|
148
|
+
console.log('');
|
|
149
|
+
console.log('To add an account, run:');
|
|
150
|
+
console.log(' google-workspace-mcp accounts add <account-name>');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
console.log(`\nConfigured accounts (${accounts.length}):\n`);
|
|
154
|
+
accounts.forEach((account, index) => {
|
|
155
|
+
console.log(`${index + 1}. ${account.name}`);
|
|
156
|
+
if (account.email) {
|
|
157
|
+
console.log(` Email: ${account.email}`);
|
|
158
|
+
}
|
|
159
|
+
console.log(` Added: ${account.addedAt}`);
|
|
160
|
+
console.log('');
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
accountsCmd
|
|
164
|
+
.command('add <name>')
|
|
165
|
+
.description('Add a new Google account')
|
|
166
|
+
.option('-c, --credentials <path>', 'Path to custom credentials.json file for this account')
|
|
167
|
+
.option('--open', 'Automatically open the authorization URL in browser (default)')
|
|
168
|
+
.option('--no-open', 'Do not automatically open browser, just print the URL')
|
|
169
|
+
.action(async (name, options) => {
|
|
170
|
+
console.log(`\nAdding account: ${name}\n`);
|
|
171
|
+
// Validate name
|
|
172
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
|
|
173
|
+
console.error('Error: Account name must contain only letters, numbers, underscores, and hyphens.');
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
await initializeAccounts();
|
|
177
|
+
// Check if account already exists
|
|
178
|
+
const accounts = await listAccounts();
|
|
179
|
+
if (accounts.some((a) => a.name === name)) {
|
|
180
|
+
console.error(`Error: Account "${name}" already exists.`);
|
|
181
|
+
console.error('Use "google-workspace-mcp auth remove <name>" first if you want to re-add it.');
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
const port = 3000;
|
|
185
|
+
console.log(`Starting OAuth flow on port ${port}...`);
|
|
186
|
+
console.log('');
|
|
187
|
+
// Default to opening browser unless --no-open is specified
|
|
188
|
+
const shouldOpenBrowser = options.open !== false;
|
|
189
|
+
try {
|
|
190
|
+
// This will block until OAuth is complete
|
|
191
|
+
await completeAddAccount(name, port, options.credentials, (authUrl) => {
|
|
192
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
193
|
+
console.log('ā AUTHORIZATION REQUIRED ā');
|
|
194
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
195
|
+
console.log('');
|
|
196
|
+
if (shouldOpenBrowser) {
|
|
197
|
+
console.log('Opening browser for authorization...');
|
|
198
|
+
console.log('');
|
|
199
|
+
console.log('If the browser does not open, visit this URL manually:');
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
console.log('Open this URL in your browser to authorize:');
|
|
203
|
+
}
|
|
204
|
+
console.log(authUrl);
|
|
205
|
+
console.log('');
|
|
206
|
+
console.log('Waiting for authorization...');
|
|
207
|
+
// Open the URL in the default browser (unless --no-open)
|
|
208
|
+
if (shouldOpenBrowser) {
|
|
209
|
+
openBrowser(authUrl);
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
console.log('');
|
|
213
|
+
console.log(`ā
Account "${name}" added successfully!`);
|
|
214
|
+
console.log('');
|
|
215
|
+
console.log('You can now use this account with the MCP server.');
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
console.error('');
|
|
219
|
+
console.error(`ā Failed to add account: ${getErrorMessage(error)}`);
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
accountsCmd
|
|
224
|
+
.command('remove <name>')
|
|
225
|
+
.description('Remove a Google account')
|
|
226
|
+
.action(async (name) => {
|
|
227
|
+
await initializeAccounts();
|
|
228
|
+
try {
|
|
229
|
+
await removeAccount(name);
|
|
230
|
+
console.log(`ā
Account "${name}" removed successfully.`);
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
console.error(`ā Failed to remove account: ${getErrorMessage(error)}`);
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
accountsCmd
|
|
238
|
+
.command('test-permissions [name]')
|
|
239
|
+
.description('Test API permissions for account(s). Tests all accounts if no name specified.')
|
|
240
|
+
.action(async (name) => {
|
|
241
|
+
await initializeAccounts();
|
|
242
|
+
const accounts = await listAccounts();
|
|
243
|
+
if (accounts.length === 0) {
|
|
244
|
+
console.log('No accounts configured.');
|
|
245
|
+
console.log('');
|
|
246
|
+
console.log('To add an account, run:');
|
|
247
|
+
console.log(' google-workspace-mcp accounts add <account-name>');
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
// Filter to specific account if name provided
|
|
251
|
+
const accountsToTest = name ? accounts.filter((a) => a.name === name) : accounts;
|
|
252
|
+
if (name && accountsToTest.length === 0) {
|
|
253
|
+
console.error(`Account "${name}" not found.`);
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
256
|
+
console.log(`\nš Testing API permissions for ${accountsToTest.length} account(s)...\n`);
|
|
257
|
+
/** Helper to handle 404 errors as success (resource doesn't exist but we have access) */
|
|
258
|
+
const handle404 = (promise) => promise.catch((e) => {
|
|
259
|
+
if (isGoogleApiError(e) && e.code === 404)
|
|
260
|
+
return { status: 200 };
|
|
261
|
+
throw e;
|
|
262
|
+
});
|
|
263
|
+
const services = [
|
|
264
|
+
{ name: 'Drive', test: async (clients) => await clients.drive.files.list({ pageSize: 1 }) },
|
|
265
|
+
{
|
|
266
|
+
name: 'Docs',
|
|
267
|
+
test: async (clients) => await handle404(clients.docs.documents.get({ documentId: 'test' })),
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
name: 'Sheets',
|
|
271
|
+
test: async (clients) => await handle404(clients.sheets.spreadsheets.get({ spreadsheetId: 'test' })),
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
name: 'Gmail',
|
|
275
|
+
test: async (clients) => await clients.gmail.users.labels.list({ userId: 'me' }),
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
name: 'Calendar',
|
|
279
|
+
test: async (clients) => await clients.calendar.calendarList.list({ maxResults: 1 }),
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
name: 'Slides',
|
|
283
|
+
test: async (clients) => await handle404(clients.slides.presentations.get({ presentationId: 'test' })),
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
name: 'Forms',
|
|
287
|
+
test: async (clients) => await handle404(clients.forms.forms.get({ formId: 'test' })),
|
|
288
|
+
},
|
|
289
|
+
];
|
|
290
|
+
let totalIssues = 0;
|
|
291
|
+
for (const account of accountsToTest) {
|
|
292
|
+
console.log(`š§ ${account.name}${account.email ? ` (${account.email})` : ''}`);
|
|
293
|
+
try {
|
|
294
|
+
const clients = await getAccountClients(account.name);
|
|
295
|
+
let accountIssues = 0;
|
|
296
|
+
for (const service of services) {
|
|
297
|
+
try {
|
|
298
|
+
await service.test(clients);
|
|
299
|
+
console.log(` ā
${service.name}`);
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
accountIssues++;
|
|
303
|
+
const message = getErrorMessage(error);
|
|
304
|
+
if (message.includes('insufficient') ||
|
|
305
|
+
message.includes('permission') ||
|
|
306
|
+
message.includes('403')) {
|
|
307
|
+
console.log(` ā ${service.name}: Permission denied`);
|
|
308
|
+
}
|
|
309
|
+
else if (message.includes('401') || message.includes('invalid_grant')) {
|
|
310
|
+
console.log(` ā ${service.name}: Token expired or revoked`);
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
console.log(` ā ${service.name}: ${message.substring(0, 60)}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (accountIssues > 0) {
|
|
318
|
+
totalIssues += accountIssues;
|
|
319
|
+
console.log(` ā ļø ${accountIssues} service(s) need attention`);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
console.log(` ā Failed to load account: ${getErrorMessage(error)}`);
|
|
324
|
+
totalIssues++;
|
|
325
|
+
}
|
|
326
|
+
console.log('');
|
|
327
|
+
}
|
|
328
|
+
if (totalIssues === 0) {
|
|
329
|
+
console.log('ā
All API permissions verified successfully!');
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
console.log(`ā ļø ${totalIssues} issue(s) found.`);
|
|
333
|
+
console.log('');
|
|
334
|
+
console.log('To fix permission issues, remove and re-add the account:');
|
|
335
|
+
console.log(' google-workspace-mcp accounts remove <name>');
|
|
336
|
+
console.log(' google-workspace-mcp accounts add <name>');
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
// === Config Commands ===
|
|
340
|
+
const configCmd = program.command('config').description('View configuration information');
|
|
341
|
+
configCmd
|
|
342
|
+
.command('path')
|
|
343
|
+
.description('Show the configuration directory path')
|
|
344
|
+
.action(() => {
|
|
345
|
+
console.log(getConfigDir());
|
|
346
|
+
});
|
|
347
|
+
configCmd
|
|
348
|
+
.command('show')
|
|
349
|
+
.description('Show current configuration')
|
|
350
|
+
.action(async () => {
|
|
351
|
+
const configDir = getConfigDir();
|
|
352
|
+
const credPath = getCredentialsPath();
|
|
353
|
+
console.log('\nGoogle Workspace MCP Server Configuration\n');
|
|
354
|
+
console.log('Configuration directory:', configDir);
|
|
355
|
+
console.log('Credentials file:', credPath);
|
|
356
|
+
console.log('');
|
|
357
|
+
// Check credentials
|
|
358
|
+
try {
|
|
359
|
+
await fs.access(credPath);
|
|
360
|
+
console.log('Credentials status: ā
Found');
|
|
361
|
+
}
|
|
362
|
+
catch {
|
|
363
|
+
console.log('Credentials status: ā Not found');
|
|
364
|
+
}
|
|
365
|
+
// List accounts
|
|
366
|
+
await initializeAccounts();
|
|
367
|
+
const accounts = await listAccounts();
|
|
368
|
+
console.log('');
|
|
369
|
+
console.log(`Accounts configured: ${accounts.length}`);
|
|
370
|
+
if (accounts.length > 0) {
|
|
371
|
+
accounts.forEach((acc, i) => {
|
|
372
|
+
console.log(` ${i + 1}. ${acc.name}${acc.email ? ` (${acc.email})` : ''}`);
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
// === Status Command ===
|
|
377
|
+
program
|
|
378
|
+
.command('status')
|
|
379
|
+
.description('Check if the server is properly configured and ready')
|
|
380
|
+
.action(async () => {
|
|
381
|
+
console.log('\nš Checking Google Workspace MCP Server status...\n');
|
|
382
|
+
let issues = 0;
|
|
383
|
+
// Check credentials
|
|
384
|
+
const credPath = getCredentialsPath();
|
|
385
|
+
try {
|
|
386
|
+
await fs.access(credPath);
|
|
387
|
+
console.log('ā
Credentials file found');
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
console.log('ā Credentials file NOT found');
|
|
391
|
+
console.log(` Expected at: ${credPath}`);
|
|
392
|
+
issues++;
|
|
393
|
+
}
|
|
394
|
+
// Check accounts
|
|
395
|
+
await initializeAccounts();
|
|
396
|
+
const accounts = await listAccounts();
|
|
397
|
+
if (accounts.length > 0) {
|
|
398
|
+
console.log(`ā
${accounts.length} account(s) configured`);
|
|
399
|
+
accounts.forEach((acc) => {
|
|
400
|
+
console.log(` - ${acc.name}${acc.email ? ` (${acc.email})` : ''}`);
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
console.log('ā ļø No accounts configured');
|
|
405
|
+
console.log(' Run: google-workspace-mcp accounts add <account-name>');
|
|
406
|
+
issues++;
|
|
407
|
+
}
|
|
408
|
+
console.log('');
|
|
409
|
+
if (issues === 0) {
|
|
410
|
+
console.log('ā
Server is ready to use!');
|
|
411
|
+
console.log('');
|
|
412
|
+
console.log('Start the server with:');
|
|
413
|
+
console.log(' google-workspace-mcp serve');
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
console.log(`ā ļø ${issues} issue(s) found. Please resolve them before using the server.`);
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
// Default command is 'serve' if no command is specified
|
|
420
|
+
program.action(() => {
|
|
421
|
+
// If no command provided, show help
|
|
422
|
+
program.help();
|
|
423
|
+
});
|
|
424
|
+
// Parse arguments
|
|
425
|
+
program.parse();
|
|
426
|
+
//# sourceMappingURL=cli.js.map
|