跳到主要内容

dsh-gmail

已验证

dsh-gmail · v0.3.1 · MIT

Connect DeepSeek Harness to Gmail and let the agent search and read mail with read-only OAuth access

安装

dsh plugin add dsh-gmail

dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南

源码

发布到 npm 但没有公开仓库。安装前请检查包内容。

标签

说明文档

dsh-gmail

Connect DeepSeek Harness (DSH) to Gmail and let the agent search your mailbox with Gmail query syntax and read individual messages. OAuth requests only the gmail.readonly scope, so the plugin can never send, edit, label, archive, or delete mail.

npm version license node

Features

  • Read-only by design — only https://www.googleapis.com/auth/gmail.readonly is requested.
  • Four agent tools — connect, check status, search, and read messages.
  • Gmail query syntaxfrom:, subject:, after:, before:, has:attachment, is:unread, and any other Gmail filter.
  • No client secret in the package — Google Web credentials live in a small Cloudflare Worker broker, never in your install.
  • PKCE + signed OAuth state — authorization codes are bound to the local machine and expire in 10 minutes.
  • Tokens stay local — access/refresh tokens are stored only on your machine; message content never passes through the broker.
  • Optional settings card — with dsh-authorize-app installed, a Gmail card appears under Settings → Connected Apps.

Requirements

  • Node.js ≥ 22
  • DeepSeek Harness with the web profile running (dsh web)

Install

dsh plugin --profile web add dsh-gmail

Then restart dsh web. For local development:

npm install
npm test
dsh plugin --profile web add file:/absolute/path/to/dsh-gmail

Connect Gmail

  1. Ask the agent to connect Gmail. It calls gmail_connect, which returns an authorization URL.
  2. Open that URL, sign in to Google, and approve read-only access.
  3. Google redirects back to the local DSH callback, which exchanges the code and stores the token.

If dsh-authorize-app is installed, you can instead open Settings → Connected Apps → Connect Gmail to get a fresh authorization URL directly.

Tools

Tool Description
gmail_connect Starts a read-only Gmail OAuth connection and returns an authorization URL.
gmail_connection_status Reports the connected account (and whether a reconnect is needed) without exposing tokens.
gmail_search Searches keywords or Gmail filters and returns message metadata (id, sender, subject, date, snippet).
gmail_read_message Reads one message body (bounded) and lists attachment filenames without downloading them.

Configuration

The plugin reads its configuration from the profile patch (cordis.patch.yml):

Key Default Description
enabled true Disable to turn the plugin off.
callbackUrl http://127.0.0.1:3080/auth/gmail/callback Local URL Google redirects back to.
tokenFile ~/.config/deepseek-harness/dsh-gmail.json Where tokens are stored (mode 0600).
maxResultChars 24000 Cap on the JSON size returned per tool call.
oauthBrokerUrl '' Origin of the OAuth broker Worker. Required before connecting.

Set the deployed broker origin in the patch before publishing:

- insert:
    - id: gmail
      name: 'dsh-gmail'
      config:
        enabled: true
        callbackUrl: 'http://127.0.0.1:3080/auth/gmail/callback'
        oauthBrokerUrl: 'https://auth.example.com'

For local testing, the DSH_GMAIL_OAUTH_BROKER_URL environment variable overrides oauthBrokerUrl.

Architecture

The npm package contains no Google client ID or client secret. A small publisher-hosted Cloudflare Worker holds the Google Web application credentials, validates a signed OAuth state, and exchanges or refreshes tokens:

┌───────────────────┐                          ┌────────────────────────────┐
│   DSH web (agent) │  PKCE verifier +         │   OAuth broker (Worker)    │
│   dsh-gmail plugin│ ─ signed state, code ──► │   holds client_id/secret   │
│                   │ ◄─── access/refresh ──── │   /oauth/google/*          │
└─────────┬─────────┘                          └──────────────┬─────────────┘
          │                                                   │
          │  Gmail API — gmail.readonly only                  │ token exchange
          │  (tokens stay on your machine)                    ▼
          └──────────────────────────────────────►   Google OAuth / Gmail API

Flow:

  1. The plugin generates a PKCE verifier/challenge and a random local state.
  2. It redirects to the broker's /oauth/google/start, which signs the state and redirects to Google.
  3. Google sends the user back to the broker's /oauth/google/callback with an authorization code.
  4. The broker verifies its signature and forwards the code to the local callbackUrl.
  5. The plugin exchanges the code (plus verifier) at /oauth/google/token, and refreshes later at /oauth/google/refresh.

PKCE is generated by the local plugin and verified by the Worker. Access and refresh tokens are returned over HTTPS and stored only on the user's machine; Gmail API requests and message content do not pass through the Worker.

Deploy your own OAuth broker

The repo ships a complete Worker under worker/. Deploy it if you are self-hosting or publishing your own package:

  1. Create a Google Cloud project, enable the Gmail API, and configure the OAuth consent screen. gmail.readonly is a restricted user-data scope, so public use requires Google verification.

  2. Deploy worker/ to Cloudflare and attach a custom domain you own, such as https://auth.example.com.

  3. Create a Google OAuth Web application client with this exact authorized redirect URI:

    https://auth.example.com/oauth/google/callback
    
  4. From worker/, set these three Worker secrets using the interactive prompt; never pass their values on the command line:

    wrangler secret put GOOGLE_CLIENT_ID
    wrangler secret put GOOGLE_CLIENT_SECRET
    wrangler secret put STATE_SIGNING_KEY
    

    STATE_SIGNING_KEY must contain at least 32 random characters.

  5. Set the same Worker origin as oauthBrokerUrl, publish the plugin, and submit the Google production app for verification. The public homepage and privacy policy should use a domain you own.

Worker development and validation:

cd worker
npm install
cp .dev.vars.example .dev.vars   # fill in the three values for local testing
npm run check                    # typecheck + unit tests + dry-run deploy
npm run deploy

The Worker exposes these endpoints:

Method Path Purpose
GET /health Reports {"ok":true} when all three secrets are configured.
GET /oauth/google/start Signs state and redirects to Google.
GET /oauth/google/callback Validates state and forwards the code to the local callback.
POST /oauth/google/token Exchanges the authorization code for tokens.
POST /oauth/google/refresh Refreshes an expired access token.

Security & privacy

  • Only the gmail.readonly scope is ever requested.
  • The plugin cannot send, edit, label, archive, or delete mail.
  • The Worker sees OAuth authorization codes and token responses, but never persists them.
  • Tokens are stored locally with mode 0600.
  • Gmail API requests and message content stay on your machine; the broker is only used for the OAuth dance.

Token storage

Tokens are stored at ~/.config/deepseek-harness/dsh-gmail.json by default ($XDG_CONFIG_HOME is honored). Override tokenFile in the profile patch when needed.

Limits

  • One Google account per configured tokenFile.
  • Search returns at most 20 messages per call.
  • Message bodies default to 20,000 characters (max 50,000) and never include downloaded attachment contents.
  • OAuth state and PKCE expire after 10 minutes.
  • Google OAuth verification is an external release requirement; installing this package cannot grant API approval.

Development

npm install
npm run build        # tsc
npm test             # build + node --test tests/*.test.mjs
npm run typecheck    # tsc --noEmit

Worker tests run in the Cloudflare vitest pool:

cd worker
npm install
npm run check        # tsc + vitest + wrangler deploy --dry-run

License

MIT © 2026 extension-hunter