Skip to main content
Add Gmail to NanoClaw as a tool (read, send, search, draft) or as a full channel that monitors your inbox and triggers the agent on new emails.

Overview

The Gmail integration uses @gongrzhe/server-gmail-autoauth-mcp as an MCP server, providing Gmail tools to your agent. It can operate in two modes:

Tool-only mode

The agent gets Gmail tools but doesn’t monitor the inbox:
  • mcp__gmail__send_email - Send emails
  • mcp__gmail__read_email - Read specific emails by ID
  • mcp__gmail__search_emails - Search with Gmail query syntax
  • mcp__gmail__create_draft - Create draft emails
  • mcp__gmail__list_labels - List Gmail labels

Channel mode

Everything from tool-only mode, plus:
  • Polls inbox for new emails (every 60 seconds)
  • Triggers agent on matching emails
  • Notifies via your main channel (e.g., WhatsApp)
  • Filters: Primary inbox only by default (excludes Promotions, Social, etc.)

Adding Gmail

Use the /add-gmail skill:
1

Run the skill

claude
/add-gmail
2

Choose mode

  • Tool-only - Agent can use Gmail tools when triggered from other channels
  • Channel mode - Agent monitors inbox and triggers on new emails
3

Apply code changes

The skill applies different changes depending on mode:Tool-only:
  • Mounts ~/.gmail-mcp in container
  • Adds Gmail MCP server to agent runner
Channel mode:
  • All of the above, plus:
  • Adds src/channels/gmail.ts (GmailChannel implementation)
  • Adds src/channels/gmail.test.ts (unit tests)
  • Merges Gmail channel into src/index.ts
  • Installs googleapis NPM package
4

Set up OAuth

Create GCP OAuth credentials and authorize Gmail access
5

Build container

Rebuild the agent container to include Gmail MCP server
6

Test

Verify Gmail tools work via your main channel

GCP OAuth setup

Gmail integration requires Google Cloud OAuth credentials.
1

Create GCP project

  1. Open console.cloud.google.com
  2. Create a new project or select existing
2

Enable Gmail API

  1. Go to APIs & ServicesLibrary
  2. Search “Gmail API”
  3. Click Enable
3

Create OAuth credentials

  1. Go to APIs & ServicesCredentials
  2. Click + CREATE CREDENTIALSOAuth client ID
  3. If prompted for consent screen:
    • Choose External
    • Fill in app name and email
    • Save
  4. Application type: Desktop app
  5. Name: anything (e.g., “NanoClaw Gmail”)
4

Download credentials

  1. Click DOWNLOAD JSON
  2. Save as gcp-oauth.keys.json
5

Move to config directory

mkdir -p ~/.gmail-mcp
cp /path/to/gcp-oauth.keys.json ~/.gmail-mcp/gcp-oauth.keys.json

Authorization

After placing the OAuth credentials file, authorize Gmail access:
npx -y @gongrzhe/server-gmail-autoauth-mcp auth
A browser window will open:
  1. Sign in to your Google account
  2. If you see “app isn’t verified” warning:
    • Click Advanced
    • Click Go to [app name] (unsafe)
    • This is normal for personal OAuth apps
  3. Grant the requested permissions
Credentials are saved to ~/.gmail-mcp/credentials.json.
The MCP server automatically refreshes OAuth tokens. You only need to authorize once unless you revoke access.

Build and restart

After authorization:
1

Clear stale agent runners

rm -r data/sessions/*/agent-runner-src 2>/dev/null || true
This ensures new group agents get the updated runner with Gmail support.
2

Rebuild container

cd container && ./build.sh
3

Rebuild and restart

npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw  # macOS
# or: systemctl --user restart nanoclaw (Linux)

Testing Gmail tools

Send a message in your main channel:
@Andy check my recent emails
or
@Andy list my Gmail labels
The agent should use the Gmail MCP tools to respond.

Check MCP server

Test the MCP server directly:
npx -y @gongrzhe/server-gmail-autoauth-mcp
If working, you’ll see the MCP server protocol handshake. Press Ctrl+C to exit.

Channel mode setup

If you chose channel mode, the agent monitors your inbox for new emails.

Default filter

By default, only emails in the Primary inbox trigger the agent:
const query = 'is:unread category:primary';
This excludes:
  • Promotions
  • Social
  • Updates
  • Forums

Custom filters

Edit src/channels/gmail.ts to customize the filter:
// Only from specific sender
const query = 'is:unread from:boss@company.com';

// Only with specific label
const query = 'is:unread label:important';

// Only matching keywords
const query = 'is:unread (urgent OR asap)';
See Gmail search operators for full query syntax.

Email notifications

When an email triggers the agent, it notifies via your main channel:
[Email from: sender@example.com]
Subject: Meeting tomorrow

Body preview (first 500 chars)...
The agent sees this notification but does not reply to the email unless you explicitly ask it to.

CLAUDE.md instructions

The skill adds these instructions to groups/main/CLAUDE.md:
## Email Notifications

When you receive an email notification (messages starting with `[Email from ...`),
inform the user about it but do NOT reply to the email unless specifically asked.
You have Gmail tools available—use them only when the user explicitly asks you to
reply, forward, or take action on an email.
This prevents the agent from auto-replying to every email.

JID format

In channel mode, emails use the gmail: prefix:
  • Email: gmail:<message-id>
Example: gmail:18d4a2f8e6c9b1a3

Implementation details

Tool-only mode

The agent runner includes the Gmail MCP server:
const mcpServers = {
  gmail: {
    command: 'npx',
    args: ['-y', '@gongrzhe/server-gmail-autoauth-mcp'],
  },
};
The ~/.gmail-mcp directory is mounted read-write into the container:
const volumes = [
  `${os.homedir()}/.gmail-mcp:/home/node/.gmail-mcp:rw`,
];

Channel mode

The Gmail channel polls for unread emails every 60 seconds:
export class GmailChannel implements Channel {
  name = 'gmail';
  
  async connect(): Promise<void> {
    this.auth = await this.authorize();
    this.gmail = google.gmail({ version: 'v1', auth: this.auth });
    
    // Poll every 60 seconds
    setInterval(() => this.checkInbox(), 60000);
  }
  
  private async checkInbox() {
    const res = await this.gmail.users.messages.list({
      userId: 'me',
      q: 'is:unread category:primary',
    });
    
    for (const message of res.data.messages || []) {
      const msg = await this.gmail.users.messages.get({
        userId: 'me',
        id: message.id!,
      });
      
      // Notify via main channel
      this.opts.onMessage(`gmail:${message.id}`, {
        id: message.id!,
        chat_jid: `gmail:${message.id}`,
        sender: this.getHeader(msg, 'From'),
        sender_name: this.getHeader(msg, 'From'),
        content: this.formatEmailNotification(msg),
        timestamp: new Date().toISOString(),
        is_from_me: false,
        is_bot_message: false,
      });
      
      // Mark as read
      await this.gmail.users.messages.modify({
        userId: 'me',
        id: message.id!,
        requestBody: { removeLabelIds: ['UNREAD'] },
      });
    }
  }
}

Troubleshooting

Re-authorize:
rm ~/.gmail-mcp/credentials.json
npx -y @gongrzhe/server-gmail-autoauth-mcp
Then rebuild and restart.
Verify the mount in src/container-runner.ts:
`${os.homedir()}/.gmail-mcp:/home/node/.gmail-mcp:rw`
Check container logs:
cat groups/main/logs/container-*.log | tail -50
Check the filter query in src/channels/gmail.ts. The default is:
q: 'is:unread category:primary'
Check logs for Gmail polling errors:
tail -f logs/nanoclaw.log | grep -i gmail
Test the MCP server directly:
npx -y @gongrzhe/server-gmail-autoauth-mcp
Should show MCP protocol handshake. If it errors, check:
  • ~/.gmail-mcp/gcp-oauth.keys.json exists
  • ~/.gmail-mcp/credentials.json exists (run auth if missing)

Available Gmail tools

The MCP server provides these tools to your agent:
ToolDescription
mcp__gmail__send_emailSend an email (to, subject, body)
mcp__gmail__read_emailRead a specific email by message ID
mcp__gmail__search_emailsSearch emails using Gmail query syntax
mcp__gmail__create_draftCreate a draft email
mcp__gmail__list_labelsList all Gmail labels

Example usage

Ask your agent:
@Andy search my emails for "project alpha" from last week
@Andy send an email to team@company.com with subject "Weekly update" and body "Here's the update..."
@Andy create a draft reply to the email from John about the meeting

Removing Gmail

To remove the Gmail skill and revert to a Gmail-free setup:
1

Find the merge commit

git log --merges --oneline | grep gmail
Look for a commit like abc1234 Merge remote-tracking branch 'upstream/skill/gmail'.
2

Revert the merge

git revert -m 1 <merge-commit>
This creates a new commit that undoes all of Gmail’s code changes.
3

Rebuild and restart

npm install
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw
See removing a skill for details.

Next steps

Skills system

Learn more about how skills work

Add Telegram

Add Telegram support to your installation

Add Discord

Add Discord support to your installation
Last modified on March 23, 2026