From 01b79289f918710df1f1b06aae807de22d25c77f Mon Sep 17 00:00:00 2001 From: Rishikesh Date: Thu, 9 Apr 2026 16:27:54 -0700 Subject: [PATCH] Add Gmail and Google Drive resource skills New AI coder skills for Gmail (email search, read, send) and Google Drive (file listing, metadata, content export) integrations. Includes MCP tool documentation, TypeScript client examples, and API-specific tips. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../shared/skills/resources_gmail/SKILL.md | 81 +++++++++++++++++ .../skills/resources_googledrive/SKILL.md | 87 +++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 plugins/shared/skills/resources_gmail/SKILL.md create mode 100644 plugins/shared/skills/resources_googledrive/SKILL.md diff --git a/plugins/shared/skills/resources_gmail/SKILL.md b/plugins/shared/skills/resources_gmail/SKILL.md new file mode 100644 index 0000000..18eefab --- /dev/null +++ b/plugins/shared/skills/resources_gmail/SKILL.md @@ -0,0 +1,81 @@ +--- +name: using-gmail-connector +description: Implements Gmail email reading, searching, and sending using generated clients and MCP tools. Use when doing ANYTHING that touches Gmail or email in any way, load this skill. +--- + +# Major Platform Resource: Gmail + +## Setting Up a Gmail Connector + +Gmail requires OAuth authentication before use. + +### When the user asks you to set up Gmail or connect their email: + +1. Call `mcp__resource-setup__request-resource-setup` with `subtype: "gmail"` — this prompts the user to authenticate with Google +2. Once setup completes, the resource is ready to use + +--- + +## Common: Interacting with Resources + +**Security**: Never connect directly to databases/APIs. Never use credentials in code. Always use generated clients or MCP tools. + +**Description field:** Always include a short `description` (~5 words) when calling any resource MCP tool, explaining what the operation does (e.g. "Search recent emails", "Send meeting invite"). This is displayed to the user in the chat UI. + +**Two ways to interact with resources:** + +1. **MCP tools** (direct, no code needed): Tools follow the pattern `mcp__resources___`. Use `mcp__resources__list_resources` to discover available resources and their IDs. +2. **Generated TypeScript clients** (for app code): Call `mcp__resource-tools__add-resource-client` with a `resourceId` to generate a typed client. Clients are created in `/clients/` (Next.js) or `/src/clients/` (Vite). + +**CRITICAL: Do NOT guess client method names or signatures.** The TypeScript clients in `@major-tech/resource-client` have strongly typed inputs and outputs. ALWAYS read the actual client source code in the generated `/clients/` directory (or the package itself) to verify available methods and their exact signatures before writing any client code. + +**Framework note**: Next.js = resource clients must be used in server-side code only (Server Components, Server Actions, API Routes). Vite = call directly from frontend. + +**Error handling**: Always check `result.ok` before accessing `result.result`. + +**Invocation keys must be static strings** — use descriptive literals like `"list-recent-emails"`, never dynamic values like `` `${date}-emails` ``. + +--- + +## MCP Tools + +- `mcp__resources__gmail_list_messages` — Search and list emails. Args: `resourceId`, `query?` (Gmail search syntax), `maxResults?`, `pageToken?`. **Returns only message IDs and thread IDs** — always follow up with `gmail_get_message` for content. +- `mcp__resources__gmail_get_message` — Get a specific email by ID with full content. Args: `resourceId`, `messageId`, `format?` (default: "full") +- `mcp__resources__gmail_send_message` — Send a plain-text email. Args: `resourceId`, `to`, `subject`, `body`, `cc?`, `bcc?`. Requires the `readwrite` scope preset. +- `mcp__resources__gmail_list_labels` — List all Gmail labels (inbox, sent, custom labels). Args: `resourceId` +- `mcp__resources__gmail_invoke` — Make any HTTP request to the Gmail API v1 (for operations not covered by other tools). Args: `resourceId`, `method`, `path`, `query?`, `body?`, `timeoutMs?` + +## TypeScript Client + +```typescript +import { gmailClient } from "./clients"; + +// invoke(method, path, invocationKey, options?) +// All paths are relative to https://gmail.googleapis.com/gmail/v1/ + +// Search for recent emails +const result = await gmailClient.invoke("GET", "users/me/messages", "search-emails", { + query: { q: "is:unread from:team@company.com", maxResults: "10" }, +}); +if (result.ok && result.result.status === 200 && result.result.body.kind === "json") { + const messages = result.result.body.value.messages; +} + +// Get a specific message +const msgResult = await gmailClient.invoke("GET", "users/me/messages/MSG_ID", "get-message", { + query: { format: "full" }, +}); +``` + +## Tips + +- **All paths are relative to `https://gmail.googleapis.com/gmail/v1/`** — e.g. use `users/me/messages`, not the full URL. +- **Gmail search syntax**: `from:user@example.com`, `subject:meeting`, `after:2024/01/01`, `is:unread`, `has:attachment`, `label:INBOX`. Combine with spaces (AND) or `OR`. +- **Message format options**: `full` (headers + parsed body), `metadata` (headers only), `minimal` (IDs only), `raw` (RFC 2822 encoded). +- **Two-step read pattern**: `list_messages` returns only IDs → use `get_message` to fetch full content. +- **Pagination**: Check `nextPageToken` in the response and pass it as `pageToken` to get the next page. +- Response structure: `{ kind: "api", status: number, body: { kind: "json", value: {...} } }` +- **Scope presets**: "readonly" (read/search only) or "readwrite" (read/search + send). Send operations fail with 403 on readonly. +- **Common paths**: `users/me/messages` (list/search), `users/me/messages/{id}` (get), `users/me/messages/send` (send), `users/me/labels` (list labels), `users/me/threads` (list threads) + +**Docs**: [Gmail API Reference](https://developers.google.com/gmail/api/reference/rest) diff --git a/plugins/shared/skills/resources_googledrive/SKILL.md b/plugins/shared/skills/resources_googledrive/SKILL.md new file mode 100644 index 0000000..edcf0cf --- /dev/null +++ b/plugins/shared/skills/resources_googledrive/SKILL.md @@ -0,0 +1,87 @@ +--- +name: using-googledrive-connector +description: Implements Google Drive file listing, reading, and management using generated clients and MCP tools. Use when doing ANYTHING that touches Google Drive, files, or documents in any way, load this skill. +--- + +# Major Platform Resource: Google Drive + +## Setting Up a Google Drive Connector + +Google Drive requires OAuth authentication before use. + +### When the user asks you to set up Google Drive or connect their files: + +1. Call `mcp__resource-setup__request-resource-setup` with `subtype: "googledrive"` — this prompts the user to authenticate with Google +2. Once setup completes, the resource is ready to use + +--- + +## Common: Interacting with Resources + +**Security**: Never connect directly to databases/APIs. Never use credentials in code. Always use generated clients or MCP tools. + +**Description field:** Always include a short `description` (~5 words) when calling any resource MCP tool, explaining what the operation does (e.g. "List project documents", "Get file contents"). This is displayed to the user in the chat UI. + +**Two ways to interact with resources:** + +1. **MCP tools** (direct, no code needed): Tools follow the pattern `mcp__resources___`. Use `mcp__resources__list_resources` to discover available resources and their IDs. +2. **Generated TypeScript clients** (for app code): Call `mcp__resource-tools__add-resource-client` with a `resourceId` to generate a typed client. Clients are created in `/clients/` (Next.js) or `/src/clients/` (Vite). + +**CRITICAL: Do NOT guess client method names or signatures.** The TypeScript clients in `@major-tech/resource-client` have strongly typed inputs and outputs. ALWAYS read the actual client source code in the generated `/clients/` directory (or the package itself) to verify available methods and their exact signatures before writing any client code. + +**Framework note**: Next.js = resource clients must be used in server-side code only (Server Components, Server Actions, API Routes). Vite = call directly from frontend. + +**Error handling**: Always check `result.ok` before accessing `result.result`. + +**Invocation keys must be static strings** — use descriptive literals like `"list-project-files"`, never dynamic values like `` `${folder}-files` ``. + +--- + +## MCP Tools + +- `mcp__resources__googledrive_list_files` — Search and list files. Args: `resourceId`, `query?` (Drive search syntax), `maxResults?`, `pageToken?` +- `mcp__resources__googledrive_get_file` — Get file metadata by ID. Args: `resourceId`, `fileId` +- `mcp__resources__googledrive_get_file_content` — Export a Google Docs/Sheets/Slides file to a specified format. Args: `resourceId`, `fileId`, `mimeType?` (default: "text/plain"). For binary files, use `googledrive_invoke` with `alt=media`. +- `mcp__resources__googledrive_list_shared_drives` — List shared drives. Args: `resourceId` +- `mcp__resources__googledrive_invoke` — Make any HTTP request to the Google Drive API v3 (for operations not covered by other tools). Args: `resourceId`, `method`, `path`, `query?`, `body?`, `timeoutMs?` + +## TypeScript Client + +```typescript +import { googleDriveClient } from "./clients"; + +// invoke(method, path, invocationKey, options?) +// All paths are relative to https://www.googleapis.com/drive/v3/ + +// List recent files +const result = await googleDriveClient.invoke("GET", "files", "list-files", { + query: { pageSize: "10", fields: "files(id,name,mimeType,modifiedTime)", orderBy: "modifiedTime desc" }, +}); +if (result.ok && result.result.status === 200 && result.result.body.kind === "json") { + const files = result.result.body.value.files; +} + +// Search for spreadsheets +const searchResult = await googleDriveClient.invoke("GET", "files", "search-spreadsheets", { + query: { q: "mimeType='application/vnd.google-apps.spreadsheet'", fields: "files(id,name)" }, +}); + +// Export a Google Doc as plain text +const exportResult = await googleDriveClient.invoke("GET", "files/FILE_ID/export", "export-doc", { + query: { mimeType: "text/plain" }, +}); +``` + +## Tips + +- **All paths are relative to `https://www.googleapis.com/drive/v3/`** — e.g. use `files`, not the full URL. +- **Drive search syntax**: `name contains 'report'`, `mimeType = 'application/vnd.google-apps.spreadsheet'`, `modifiedTime > '2024-01-01'`, `'FOLDER_ID' in parents`, `trashed = false`. Combine with `and`/`or`. +- **Google Workspace MIME types**: `application/vnd.google-apps.document` (Docs), `application/vnd.google-apps.spreadsheet` (Sheets), `application/vnd.google-apps.presentation` (Slides), `application/vnd.google-apps.folder` (Folder) +- **Export MIME types** (for `get_file_content`): `text/plain`, `text/csv`, `application/pdf`, `application/vnd.openxmlformats-officedocument.wordprocessingml.document` (.docx), `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` (.xlsx) +- **Binary file download**: Use `googledrive_invoke` with path `files/{id}?alt=media` to download non-Google files directly. +- **Pagination**: Check `nextPageToken` in the response and pass it as `pageToken` to get the next page. +- **Fields parameter**: Use `fields` query param to limit response size, e.g. `fields=files(id,name,mimeType,modifiedTime,size)`. +- Response structure: `{ kind: "api", status: number, body: { kind: "json", value: {...} } }` +- **Scope presets**: "readonly" (view files) or "readwrite" (view all files + manage app-created files). Write operations fail with 403 on readonly. + +**Docs**: [Google Drive API Reference](https://developers.google.com/drive/api/reference/rest/v3)