This is an AI-powered Virtual Assistant that manages your administrative tasks through a Model Context Protocol (MCP) server deployed on Cloudflare Workers. It integrates with Gmail, Google Calendar, Google Drive, Notion, and Slack to handle routine admin work, keeping you focused on building and selling.
This MCP server acts as an AI-powered virtual assistant that manages administrative tasks by integrating with Gmail, Google Calendar, Google Drive, No...
14export const driveTools = {
15 list_drive_files: { ... },
16 create_drive_text_file: { ... },
17 get_drive_file_metadata: { ... },
18 get_drive_file_content: { ... },
19 delete_drive_file: { ... },
20};// Exploitable if MCP is exposed to untrusted prompts or if LLM is compromised. The Drive integration token provides broad access to the user's Google Drive.
30export const gmailTools = {
31 send_email: {
32 schema: SendEmailSchema,
33 handler: sendEmail,
34 description: "Send a new email via Gmail",
35 },
36 delete_email: {
37 schema: DeleteEmailSchema,
38 handler: deleteEmail,
39 description: "Permanently delete an email",
40 },
41 batch_delete_emails: {
42 schema: BatchDeleteEmailsSchema,
43 handler: batchDeleteEmails,
44 description: "Batch permanently delete multiple emails",
45 },
46 // ...
47};// Exploitable if MCP is exposed to untrusted prompts or if LLM is compromised. The Gmail integration token provides full access to the user's Gmail account.
724private async executeNotionOperation(notionClient: Client, operation: any, args: any): Promise<any> {
725 const { method, path } = operation;
726 let url = path;
727 const requestOptions: any = { method: method.toUpperCase() };
728 if (operation.parameters) {
729 for (const param of operation.parameters) {
730 if (param.in === "path" && args[param.name]) {
731 url = url.replace(`{${param.name}}`, args[param.name]);
732 }
733 }
734 }
735 if (method.toLowerCase() === "get") {
736 const queryParams = new URLSearchParams();
737 if (operation.parameters) {
738 for (const param of operation.parameters) {
739 if (param.in === "query" && args[param.name] !== undefined) {
740 queryParams.append(param.name, args[param.name]);
741 }
742 }
743 }
744 for (const [key, value] of Object.entries(args)) {
745 if (value !== undefined && !operation.parameters?.some((p: any) => p.name === key && p.in === "path")) {
746 queryParams.append(key, String(value));
747 }
748 }
749 if (queryParams.toString()) {
750 url += "?" + queryParams.toString();
751 }
752 } else {
753 requestOptions.body = args;
754 }
755 const operationId = operation.operationId || operation.methodName;
756 switch (operationId) {
757 case "get-user":
758 return await notionClient.users.retrieve({ user_id: args.user_id });
759 // ... many cases
760 default:
761 throw new Error(`Unsupported operation: ${operationId}`);
762 }
763 }// Exploitable if MCP is exposed to untrusted prompts or if LLM is compromised. The Notion integration token provides broad access to the user's Notion workspace.
24export const calendarTools = {
25 create_event: { ... },
26 update_event: { ... },
27 delete_event: { ... },
28 quick_add_event: { ... },
29 freebusy_query: { ... },
30 // ...
31};// Exploitable if MCP is exposed to untrusted prompts or if LLM is compromised. The Calendar integration token provides full access to the user's calendars.
222export const uploadFile: SlackTool<z.infer<typeof UploadFileSchema>> = async ({ slack }, args) => {
223 const options: any = {
224 channels: args.channels.join(","),
225 content: args.content,
226 filename: args.filename,
227 };
228 if (args.title) options.title = args.title;
229 if (args.initialComment) options.initial_comment = args.initialComment;
230 const response = await slack.files.uploadV2(options);
231 return {
232 content: [{ type: "text", text: JSON.stringify(response, null, 2) }],
233 };
234};// Exploitable if MCP is exposed to untrusted prompts or if LLM is compromised. The Slack integration token may have broad permissions to post and upload files.
91export const queryDatabase: NotionTool<z.infer<typeof QueryDatabaseSchema>> = async ({ notion }, args) => {
92 const queryParams: any = { database_id: args.databaseId, page_size: args.pageSize };
93 if (args.filterBy) {
94 try {
95 queryParams.filter = JSON.parse(args.filterBy);
96 } catch (e) {
97 return { content: [{ type: "text", text: `Error parsing filter: ${e}` }] };
98 }
99 }
100 if (args.sortBy) {
101 try {
102 queryParams.sorts = JSON.parse(args.sortBy);
103 } catch (e) {
104 return { content: [{ type: "text", text: `Error parsing sorts: ${e}` }] };
105 }
106 }
107 const response = await notion.databases.retrieve(queryParams);
108 return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] };
109};// Exploitable if MCP is exposed to untrusted prompts or if LLM is compromised. The Notion integration token may have broad access.
23export const postMessage: SlackTool<z.infer<typeof PostMessageSchema>> = async ({ slack }, args) => {
24 const options: any = { channel: args.channel, text: args.text };
25 if (args.threadTs) { options.thread_ts = args.threadTs; }
26 if (args.blocks) {
27 try {
28 options.blocks = JSON.parse(args.blocks);
29 } catch (e) {
30 return { content: [{ type: "text", text: `Error parsing blocks: ${e}` }] };
31 }
32 }
33 const response = await slack.chat.postMessage(options);
34 return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] };
35};// Exploitable if MCP is exposed to untrusted prompts or if LLM is compromised. The Slack integration token may have broad permissions.