{
  "slug": "com-pulsemcp-gmail",
  "name": "com.pulsemcp/gmail",
  "title": "gmail",
  "description": "MCP server for Gmail with OAuth2 (personal) and service account (Workspace) support.",
  "version": "0.4.12",
  "publishedAt": "2026-08-30T15:08:07.811368Z",
  "updatedAt": "2026-08-30T15:08:07.811368Z",
  "repoUrl": "https://github.com/pulsemcp/mcp-servers",
  "websiteUrl": null,
  "namespace": {
    "type": "domain",
    "owner": "pulsemcp.com"
  },
  "kind": "local",
  "packages": [
    {
      "registryType": "npm",
      "identifier": "gmail-workspace-mcp-server",
      "version": "0.4.12",
      "transport": "stdio",
      "runtimeHint": "npx"
    }
  ],
  "remotes": [],
  "envVars": [
    {
      "name": "GMAIL_OAUTH_CLIENT_ID",
      "isSecret": true,
      "isRequired": false,
      "description": "OAuth2 client ID from Google Cloud Console (for personal Gmail accounts)."
    },
    {
      "name": "GMAIL_OAUTH_CLIENT_SECRET",
      "isSecret": true,
      "isRequired": false,
      "description": "OAuth2 client secret from Google Cloud Console."
    },
    {
      "name": "GMAIL_OAUTH_REFRESH_TOKEN",
      "isSecret": true,
      "isRequired": false,
      "description": "Refresh token from the OAuth2 setup script."
    },
    {
      "name": "GMAIL_SERVICE_ACCOUNT_CLIENT_EMAIL",
      "isSecret": false,
      "isRequired": false,
      "description": "Service account email address (for Google Workspace)."
    },
    {
      "name": "GMAIL_SERVICE_ACCOUNT_PRIVATE_KEY",
      "isSecret": true,
      "isRequired": false,
      "description": "Service account private key in PEM format (for Google Workspace)."
    },
    {
      "name": "GMAIL_IMPERSONATE_EMAIL",
      "isSecret": false,
      "isRequired": false,
      "description": "Email address to impersonate (required for service account mode)."
    },
    {
      "name": "GMAIL_ENABLED_TOOLGROUPS",
      "isSecret": false,
      "isRequired": false,
      "description": "Comma-separated list of tool groups to enable (readonly, readwrite, readwrite_external)."
    }
  ],
  "category": "communication",
  "subcategory": "email",
  "company": "",
  "categoryAuto": true,
  "checks": [
    {
      "id": "source-linked",
      "label": "Source repository linked",
      "result": "pass",
      "detail": "https://github.com/pulsemcp/mcp-servers"
    },
    {
      "id": "version-pinned",
      "label": "Version pinned",
      "result": "pass",
      "detail": "Every package has an explicit version"
    },
    {
      "id": "secrets-requested",
      "label": "Secrets requested",
      "result": "warn",
      "detail": "Asks for 4 secrets: GMAIL_OAUTH_CLIENT_ID, GMAIL_OAUTH_CLIENT_SECRET, GMAIL_OAUTH_REFRESH_TOKEN, GMAIL_SERVICE_ACCOUNT_PRIVATE_KEY"
    },
    {
      "id": "known-registry",
      "label": "Known package registry",
      "result": "pass",
      "detail": "All packages come from npm, PyPI, OCI, NuGet or MCPB"
    },
    {
      "id": "namespace",
      "label": "Namespace ownership",
      "result": "info",
      "detail": "Name verified via domain pulsemcp.com"
    },
    {
      "id": "meta-text",
      "label": "Registry text aimed at the AI",
      "result": "pass",
      "detail": "Description and settings contain no hidden characters or instructions to the AI"
    },
    {
      "id": "install-scripts",
      "label": "Install scripts",
      "result": "pass",
      "detail": "gmail-workspace-mcp-server@0.4.12 runs nothing at install"
    },
    {
      "id": "code-flags",
      "label": "Code red flags",
      "result": "pass",
      "detail": "Read 61 files in gmail-workspace-mcp-server@0.4.12: no obfuscation, encoded execution, credential reads or data-collection endpoints found"
    },
    {
      "id": "ai-text",
      "label": "Text aimed at the AI",
      "result": "pass",
      "detail": "No hidden characters or instructions to the AI in 61 files, including comments and the README"
    }
  ],
  "scannedAt": "2026-10-29",
  "level": "Scanned",
  "install": [
    {
      "label": "Claude Desktop (npm)",
      "kind": "claude_desktop_json",
      "text": "{\n  \"mcpServers\": {\n    \"gmail\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"-y\",\n        \"gmail-workspace-mcp-server@0.4.12\"\n      ]\n    }\n  }\n}"
    }
  ],
  "curated": true,
  "stars": 81,
  "archived": false,
  "pushedAt": "2026-10-09T17:32:15Z",
  "review": {
    "package": "gmail-workspace-mcp-server",
    "version": "0.4.12",
    "at": "2026-10-31",
    "files": 58,
    "lines": 4619,
    "verdict": "pass-with-notes",
    "summary": "Lets an AI assistant search and read your Gmail, download attachments, label or archive messages, manage drafts and send email. It talks only to Google's Gmail and sign-in servers using the credentials you configure; there is no telemetry. Sending is on by default but asks you to confirm each email first unless you turn that off, and the Google access it requests covers reading, changing and sending mail.",
    "hosts": [
      {
        "host": "gmail.googleapis.com (/gmail/v1/users/me/*)",
        "when": "Only when a tool is called",
        "sends": "OAuth access token; message/draft IDs, search queries, label changes, full composed emails (to/cc/bcc/subject/body) for drafts and sends; profile lookup for the account email"
      },
      {
        "host": "oauth2.googleapis.com / accounts.google.com (via google-auth-library)",
        "when": "When a tool needs an access token (first call / refresh), and during the optional oauth-setup CLI",
        "sends": "OAuth client ID + secret + refresh token, or a service-account signed JWT; authorization code during setup"
      },
      {
        "host": "localhost:<PORT, default 3000> (local HTTP listener)",
        "when": "Only during the manual 'oauth-setup' CLI subcommand, for up to 5 minutes",
        "sends": "Receives the OAuth redirect code from the browser"
      },
      {
        "host": "ELICITATION_REQUEST_URL / ELICITATION_POLL_URL (user-configured, none by default)",
        "when": "Only when send_email is called, the user configured these URLs, and the client lacks native elicitation (or ELICITATION_PREFER_HTTP_FALLBACK=true)",
        "sends": "Confirmation prompt text including To, Subject, CC, BCC of the email (or draft ID), request ID, optional session ID"
      }
    ],
    "env": [
      {
        "name": "GMAIL_OAUTH_CLIENT_ID",
        "sent_to": "Google OAuth token endpoint"
      },
      {
        "name": "GMAIL_OAUTH_CLIENT_SECRET",
        "sent_to": "Google OAuth token endpoint"
      },
      {
        "name": "GMAIL_OAUTH_REFRESH_TOKEN",
        "sent_to": "Google OAuth token endpoint"
      },
      {
        "name": "GMAIL_SERVICE_ACCOUNT_CLIENT_EMAIL",
        "sent_to": "Google OAuth token endpoint (JWT issuer)"
      },
      {
        "name": "GMAIL_SERVICE_ACCOUNT_PRIVATE_KEY",
        "sent_to": "not sent; used locally to sign the JWT"
      },
      {
        "name": "GMAIL_IMPERSONATE_EMAIL",
        "sent_to": "Google OAuth (JWT subject); also used as the From header"
      },
      {
        "name": "GMAIL_ENABLED_TOOLGROUPS",
        "sent_to": "not sent; local config (readonly, readwrite, readwrite_external)"
      },
      {
        "name": "ELICITATION_ENABLED / _REQUEST_URL / _POLL_URL / _TTL_MS / _POLL_INTERVAL_MS / _SESSION_ID / _PREFER_HTTP_FALLBACK",
        "sent_to": "Session ID goes to the user-configured elicitation URL; the rest are local config"
      },
      {
        "name": "PORT",
        "sent_to": "not sent; local port for the oauth-setup callback"
      },
      {
        "name": "NODE_ENV / DEBUG",
        "sent_to": "not sent; debug logging to stderr"
      }
    ],
    "local": "Reads its own package.json. download_email_attachments (default inline=false) writes attachments to the hard-coded path /tmp/gmail-attachments-<sanitized email id>/<basename(filename)>; path traversal is blocked by basename() and ID sanitising (on Windows '/tmp' resolves to <drive>:\\tmp). The oauth-setup subcommand opens a local HTTP server and prints credentials to stdout. No other filesystem access.",
    "exec": "None. No child_process, eval or Function. Dynamic import() is only for the package's own fixed relative modules.",
    "telemetry": "None. No analytics. The optional HTTP elicitation fallback only contacts URLs the user sets; off by default.",
    "tools": [
      "list_email_conversations",
      "get_email_conversation",
      "search_email_conversations",
      "download_email_attachments",
      "list_draft_emails",
      "change_email_conversation",
      "upsert_draft_email",
      "send_email"
    ],
    "toolText": "clean",
    "deps": [
      "@modelcontextprotocol/sdk",
      "zod",
      "google-auth-library",
      "@pulsemcp/mcp-elicitation (bundled in node_modules; its code was read and is counted)"
    ],
    "findings": [
      {
        "severity": "note",
        "at": "shared/tools.js:18-37",
        "what": "send_email (can email anyone) is enabled by default because all tool groups are on unless GMAIL_ENABLED_TOOLGROUPS is set. Its description clearly says it sends immediately and cannot be undone."
      },
      {
        "severity": "note",
        "at": "shared/tools/send-email.js:119-179; node_modules/@pulsemcp/mcp-elicitation/build/elicitation.js:136-159",
        "what": "Good: send_email asks the user to confirm (MCP elicitation) by default and fails closed on anything but 'accept'; if the client has no elicitation support and no fallback URL is set, sending errors out. ELICITATION_ENABLED=false turns the confirmation off, after which mail is sent without asking."
      },
      {
        "severity": "note",
        "at": "shared/server.js:8-13; build/oauth-setup.js:13-18",
        "what": "Requests broad Gmail scopes (gmail.readonly, gmail.modify, gmail.compose, gmail.send) even when only read-only tools are enabled."
      },
      {
        "severity": "note",
        "at": "shared/gmail-client/lib/mime-utils.js:33-51",
        "what": "To/Cc/Bcc/Subject are placed into raw MIME headers without stripping CR/LF. An AI-supplied ASCII subject or recipient containing a newline could add extra headers (e.g. a hidden Bcc) that the confirmation prompt does not list under BCC. Requires the AI itself to be steered, e.g. by prompt injection."
      },
      {
        "severity": "note",
        "at": "shared/tools/draft-email.js:141-150",
        "what": "upsert_draft_email with delete=true permanently deletes a draft with no confirmation."
      },
      {
        "severity": "info",
        "at": "build/oauth-setup.js:53,113-132",
        "what": "The manual oauth-setup command prints the client secret and refresh token to the terminal (intended, so the user can copy them into config). Its callback server listens on all interfaces (listen(port) with no host) and uses no OAuth state parameter; exposure is limited to the 5-minute setup window."
      },
      {
        "severity": "info",
        "at": "node_modules/@pulsemcp/mcp-elicitation/build/elicitation.js:47-100",
        "what": "Optional HTTP confirmation fallback sends recipients and subject to user-configured URLs; off unless configured."
      },
      {
        "severity": "info",
        "at": "shared/tools/download-email-attachments.js:141",
        "what": "Attachments are saved under hard-coded /tmp rather than os.tmpdir(); on Windows this becomes C:\\tmp. Files are not cleaned up."
      },
      {
        "severity": "info",
        "at": "shared/tools/get-email-conversation.js:135-195",
        "what": "Email bodies are returned verbatim to the AI; mail from strangers can contain prompt-injection text that tries to make the AI send mail. The default send confirmation mitigates this."
      },
      {
        "severity": "info",
        "at": "(package)",
        "what": "package.json was not part of the review set; the dependency list is inferred from imports, and install scripts (if any) could not be checked."
      }
    ]
  },
  "health": {
    "score": 61,
    "parts": {
      "popularity": 0.43138892751261965,
      "activity": 0.6674452394758004,
      "issues": 0.7096774193548387,
      "security": 0.8
    },
    "fail": 0,
    "warn": 1,
    "raw": {
      "stars": 81,
      "forks": 10,
      "downloads": 163,
      "hn": {
        "n": 0,
        "pts": 0,
        "t": []
      },
      "issuesOpen": 27,
      "issuesClosed": 66,
      "prsMerged": 491,
      "commits90": 1,
      "release": "2025-07-03T16:10:39Z",
      "pushed": "2026-10-09T17:32:15Z",
      "growth": null,
      "growthDays": null,
      "archived": false
    },
    "at": "2026-10-31T07:42:38.200Z"
  }
}
