Skip to main content
Glama
praneethpalla

Yahoo Mail MCP Server

Yahoo Mail MCP Server

A Model Context Protocol (MCP) server that provides full email management for Yahoo Mail via IMAP. It works with any MCP client (Claude, ChatGPT, Cursor, VS Code, and others): local stdio transport for desktop apps, and Streamable HTTP (plus legacy SSE) for remote access.

Forked from jtokib/yahoo-mail-mcp-server (MIT). The original provides the IMAP server, UID-based email tools, OAuth 2.0 flow, and Render/Docker deployment. This fork adds the features below.

What's New in This Fork

  • Draft emails from any AI assistant: create_draft, create_reply_draft (threaded, with reply-all and quoting), and update_draft, so the assistant can revise a draft from your feedback. Drafts land in Yahoo Mail's Drafts folder; nothing is ever sent without you.

  • Attachments: download_attachments saves files to disk, and read_email lists attachment names, types, and sizes.

  • Streamable HTTP: the current MCP transport at /mcp, stateless, so it survives cold starts and sleeping hosts. Legacy SSE still works.

  • One shared IMAP login: tool calls reuse a single Yahoo login instead of logging in on every call, which avoids Yahoo's login throttling.

  • Faster bulk actions: read/unread, flag, archive, and move run as one IMAP command; delete stays one email at a time.

  • Bug fixes: empty read_email results for large emails, multi-email reads returning only the first email, sizes always 0, invalid search dates silently ignored, and a missing isError flag on errors.

  • Sign-in page with MFA: connecting an app opens a sign-in page (username, password, and a 6-digit authenticator code), like other connectors. Passwords are stored only as scrypt hashes, codes can't be reused, and 5 failed attempts lock an address out for 15 minutes. npm run setup-login creates the settings.

  • OAuth hardening: signed access tokens that really expire after 1 hour, plus refresh tokens so clients stay connected without re-login, even across restarts and Render sleep. Authorization codes are random, single-use, and valid for 60 seconds. The redirect_uri check matches the exact hostname (the old substring check accepted URLs like https://evil.example/?claude.ai), and HTTP mode refuses to start without OAuth configured.

  • Offline test suite: npm test runs 53 tests against fake IMAP servers and a local HTTP server, with no real email login.

Related MCP server: Yahoo Mail MCP Server

Project Status

Area

Status

Local mode (stdio) with Claude Desktop

✅ Tested against a real Yahoo mailbox: folders, search, multi-email reads, attachment download, new/reply/revised drafts, bulk flag/unflag, error handling

Other local clients (Cursor, VS Code, Codex CLI, ...)

⚠️ Should work (standard MCP stdio), not yet tested

Hosted mode (Streamable HTTP, OAuth, sign-in page with MFA)

⚠️ Experimental. Covered by the offline test suite (53 tests, including the full sign-in and token flow and the official MCP SDK client), but not yet tested end-to-end on Render or with Claude.ai / ChatGPT connectors

ChatGPT connectors

❓ Unverified. This server doesn't support dynamic client registration, so the client must let you enter a client ID and secret

Feedback and issue reports from hosted setups are very welcome.

Where Your Credentials Live (Read This First)

This server needs your Yahoo app password: a 16-character password Yahoo generates for one app (like a personal access token). It gives full mailbox access (read, move, delete, drafts), bypasses 2-step verification, and never expires until you revoke it. Where it lives depends on how you run the server:

Setup

Who can see the app password

Who can see your email content

Use it from

Local (recommended): Claude Desktop, Cursor, VS Code, Codex CLI start the server on your computer

Only your computer (in .env)

Only your computer

That computer's desktop apps

Hosted (optional): Render, Fly.io, a VPS, etc.

The hosting provider and anyone with access to your hosting account

Passes through the host's servers while tools run

Anywhere: Claude.ai web/mobile, ChatGPT, other remote MCP clients

Local setup: the server runs as a local process, talks to the app through a pipe (stdio), and opens no network port. Your credentials never leave your machine. No sign-in page is needed because nothing is reachable from outside.

Hosted setup: the server must hold the app password in readable form to log in to Yahoo, so you are trusting the host. The sign-in page, MFA, and OAuth protect who can use your server; they don't hide anything from the host itself. What the host holds:

Setting

Stored on the host as

Notes

YAHOO_APP_PASSWORD

Readable

Required to log in to Yahoo

OAUTH_CLIENT_SECRET

Readable

Signs access tokens; changing it logs out every app

AUTH_TOTP_SECRET

Readable

Required to check authenticator codes

Your sign-in password

Hash only (scrypt)

The real password is never stored anywhere

If you host it:

  1. Create a separate app password just for the host (e.g. named MCP Render), so you can revoke it without affecting anything else.

  2. Turn on 2-step verification for your hosting and GitHub accounts. Someone breaking into those is a more likely risk than the host itself.

  3. Store every credential as a secret environment variable, never in the repository.

  4. Revoke the app password at Yahoo account security whenever you stop hosting or suspect a leak, and change OAUTH_CLIENT_SECRET to disconnect every app immediately.

  5. Only host if you need web, mobile, or ChatGPT access. If you only use desktop apps, stay local.

Logging: the server logs request paths, OAuth events, and connection errors. It is written not to log passwords, tokens, secrets, email addresses, or email content.

Never sent, never shared: the server has no send-mail capability (drafts only), and each deployment serves one mailbox: yours. Nobody else's credentials are involved, and you never need to give yours to anyone else's server.

Features

  • Secure OAuth 2.0 Authentication: Protect your remote MCP server with OAuth 2.0 authorization code flow with PKCE

  • UID-Based Operations: Uses permanent IMAP UIDs that don't change when emails are deleted (v3.0.0+)

  • Full Email Management: Complete email operations with batch processing support

  • Fifteen Tools:

    • list_emails: List recent emails with enriched metadata (size, flags, attachments) and pagination

    • read_email: Read the full content of emails (batch support)

    • search_emails: Advanced search with filters (date ranges, sender, unread status)

    • list_folders: Discover all available IMAP folders

    • delete_emails: Move emails to Trash (soft delete, recoverable)

    • archive_emails: Archive emails for long-term storage

    • mark_as_read: Mark emails as read

    • mark_as_unread: Mark emails as unread

    • flag_emails: Flag emails as important/starred

    • unflag_emails: Remove flag from emails

    • move_emails: Move emails to any folder

    • download_attachments: Save an email's attachments to disk

    • create_draft: Save a new email as a draft (never sent)

    • create_reply_draft: Save a threaded reply as a draft (never sent)

    • update_draft: Revise a draft, changing only the fields you pass

  • Drafts, Not Sending: The server never sends email. Drafts appear in Yahoo Mail's Drafts folder for you to review and send, and the MCP client can revise them from your feedback

  • One Shared IMAP Login: Tool calls reuse one Yahoo login (logged out after 5 minutes idle) instead of logging in every time, which avoids Yahoo's login throttling

  • Enriched Metadata: All emails include UID, size, flags, hasAttachments, and folder information

  • Advanced Search: Filter by date range, sender, unread status, and search across any folder

  • Batch Operations: All management operations support processing multiple emails at once with accurate success/failure tracking

  • Transport Modes:

    • stdio: For local desktop MCP clients (Claude Desktop, Cursor, VS Code, ...)

    • http: For remote access. Serves stateless Streamable HTTP at /mcp (current MCP standard) and legacy SSE at /mcp/sse

  • Cross-Platform: Works on both Windows and Linux development environments

  • Docker Support: Containerized deployment with Docker and Docker Compose

  • Cloud Ready: Configured for easy deployment to Render.com with OAuth security

Prerequisites

For Local Development

  • Node.js: Version 18.0.0 or higher

  • Yahoo Mail Account: With app-specific password enabled

  • Git: For version control

For Docker Development/Deployment

  • Docker: Latest version

  • Docker Compose: Latest version (included with Docker Desktop on Windows/Mac)

For Render.com Deployment

  • GitHub Account: To host your repository

  • Render.com Account: Free tier available at https://render.com

Quick Start

1. Clone and Setup

# Clone the repository
git clone https://github.com/praneethpalla/yahoo-mail-mcp.git
cd yahoo-mail-mcp

# Copy environment template
cp .env.example .env

2. Get Yahoo Mail App Password

  1. Go to https://login.yahoo.com/account/security

  2. Click "Generate app password" or "Manage app passwords"

  3. Select "Other App" and enter "MCP Server"

  4. Copy the generated 16-character password

3. Configure Environment

Edit .env file with your credentials:

YAHOO_EMAIL=your.email@yahoo.com
YAHOO_APP_PASSWORD=your16charpassword
TRANSPORT_MODE=stdio  # or 'sse' for HTTP mode
PORT=3000

4. Install Dependencies

Windows (PowerShell):

npm install

Linux/macOS (Bash):

npm install

5. Run Locally

stdio mode (for Claude Desktop):

npm run start:stdio

SSE mode (for testing HTTP endpoint):

npm run start:sse

Development mode (with auto-reload):

npm run dev

Docker Usage

Build and Run with Docker

Windows (PowerShell):

# Build the image
npm run docker:build

# Run the container
npm run docker:run

# Or use Docker Compose (recommended)
npm run docker:compose:up

# View logs
npm run docker:compose:logs

# Stop containers
npm run docker:compose:down

Linux/macOS (Bash):

# Build the image
npm run docker:build

# Run the container
npm run docker:run

# Or use Docker Compose (recommended)
npm run docker:compose:up

# View logs
npm run docker:compose:logs

# Stop containers
npm run docker:compose:down

Manual Docker Commands

Windows (PowerShell):

# Build
docker build -t yahoo-mail-mcp .

# Run
docker run -p 3000:3000 `
  -e YAHOO_EMAIL=your.email@yahoo.com `
  -e YAHOO_APP_PASSWORD=yourpassword `
  -e TRANSPORT_MODE=sse `
  yahoo-mail-mcp

# Or with Docker Compose
docker-compose up -d

Linux/macOS (Bash):

# Build
docker build -t yahoo-mail-mcp .

# Run
docker run -p 3000:3000 \
  -e YAHOO_EMAIL=your.email@yahoo.com \
  -e YAHOO_APP_PASSWORD=yourpassword \
  -e TRANSPORT_MODE=sse \
  yahoo-mail-mcp

# Or with Docker Compose
docker-compose up -d

Testing the Server

Test Health Endpoint

Windows (PowerShell):

# Using npm script
npm run test:health

# Using curl (if installed)
curl http://localhost:3000/health

# Using PowerShell
Invoke-WebRequest -Uri http://localhost:3000/health | Select-Object -Expand Content

Linux/macOS (Bash):

# Using npm script
npm run test:health

# Using curl
curl http://localhost:3000/health

Test the Streamable HTTP Endpoint

With OAuth configured, first get a token, then call /mcp:

TOKEN=$(curl -s -X POST http://localhost:3000/oauth/token \
  -H 'Content-Type: application/json' \
  -d '{"grant_type":"client_credentials","client_id":"YOUR_ID","client_secret":"YOUR_SECRET"}' | node -pe 'JSON.parse(require("fs").readFileSync(0)).access_token')

curl -s -X POST http://localhost:3000/mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Run the Offline Test Suite

npm test

The tests use fake IMAP servers and a local HTTP server with dummy credentials, so they never log in to Yahoo.

Test SSE Endpoint (legacy)

Windows (PowerShell):

# Using npm script
npm run test:sse

# Using curl
curl http://localhost:3000/mcp/sse

# Using PowerShell
Invoke-WebRequest -Uri http://localhost:3000/mcp/sse

Linux/macOS (Bash):

# Using npm script
npm run test:sse

# Using curl
curl http://localhost:3000/mcp/sse

Deploying to Render.com

Experimental: hosted mode passes the offline tests but hasn't been tested end-to-end on Render yet. See Project Status.

Before you host: the host will hold your Yahoo app password in readable form. Read Where Your Credentials Live, and use a separate, revocable app password for the host.

Step 1: Prepare Your Repository

Windows (PowerShell):

# Initialize git (if not already done)
git init

# Add all files
git add .

# Commit
git commit -m "Initial commit: Yahoo Mail MCP Server"

# Create GitHub repository at https://github.com/new
# Then push to GitHub
git remote add origin https://github.com/yourusername/yahoo-mail-mcp-server.git
git branch -M main
git push -u origin main

Linux/macOS (Bash):

# Initialize git (if not already done)
git init

# Add all files
git add .

# Commit
git commit -m "Initial commit: Yahoo Mail MCP Server"

# Create GitHub repository at https://github.com/new
# Then push to GitHub
git remote add origin https://github.com/yourusername/yahoo-mail-mcp-server.git
git branch -M main
git push -u origin main

Step 2: Deploy to Render

  1. Sign up/Login to Render.com

  2. Connect GitHub Repository

    • Click "New +" button in top right

    • Select "Web Service"

    • Click "Connect GitHub" and authorize Render

    • Select your yahoo-mail-mcp-server repository

  3. Configure the Service

    • Name: yahoo-mail-mcp-server (or your preferred name)

    • Runtime: Docker

    • Region: Choose closest to you (Oregon, Frankfurt, Singapore, Ohio)

    • Branch: main

    • Plan: Free (or Starter for production)

  4. Set Environment Variables

    In the "Environment" section, click "Add Environment Variable" and add:

    Key

    Value

    How to Generate

    NODE_ENV

    production

    -

    TRANSPORT_MODE

    http

    -

    TRUST_PROXY

    1

    - (Render runs behind one proxy; needed for per-address sign-in lockouts)

    YAHOO_EMAIL

    your.email@yahoo.com

    Your Yahoo email address

    YAHOO_APP_PASSWORD

    your16charpassword

    See "Get Yahoo Mail App Password" section

    OAUTH_CLIENT_ID

    32-char-hex-string

    Run: openssl rand -hex 16

    OAUTH_CLIENT_SECRET

    64-char-hex-string

    Run: openssl rand -hex 32

    AUTH_USERNAME

    your sign-in name

    Run: npm run setup-login -- --out ~/yahoo-mcp-login.txt

    AUTH_PASSWORD_HASH

    scrypt$...

    From the same file (a hash, never the password itself)

    AUTH_TOTP_SECRET

    base32 secret

    From the same file; also add it to your authenticator app

    npm run setup-login asks for a username and password (hidden while typing), creates an authenticator secret, and writes all three AUTH_* values to the file you choose (readable only by you). Add the secret to Google Authenticator, 1Password, Authy, or similar via "Enter a setup key", then delete the file once everything is copied.

    Important:

    • Mark YAHOO_EMAIL, YAHOO_APP_PASSWORD, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, AUTH_PASSWORD_HASH, and AUTH_TOTP_SECRET as "Secret"

    • The server refuses to start in HTTP mode without the OAuth and AUTH_USERNAME/AUTH_PASSWORD_HASH settings

    • PORT is automatically set by Render, don't add it manually

    • Save the OAuth credentials - you'll need them to configure Claude Desktop

  5. Deploy

    • Click "Create Web Service"

    • Render will automatically build and deploy your Docker container

    • Wait for deployment to complete (first build takes 5-10 minutes)

  6. Get Your Service URL

    • Once deployed, you'll get a URL like: https://yahoo-mail-mcp-server.onrender.com

    • Test it by visiting: https://yahoo-mail-mcp-server.onrender.com/health

Step 3: Connect to Claude Desktop

Note: Remote MCP servers require a Claude Pro, Max, Team, or Enterprise plan.

  1. Open Claude Desktop

    • Launch the Claude Desktop app on your computer

  2. Add MCP Connector

    • Click on your profile icon or menu

    • Select "Settings"

    • Navigate to "Connectors" section

    • Click "Add Custom Connector"

  3. Configure the Connector

    • Name: Yahoo Mail

    • URL: https://your-service-name.onrender.com/mcp

    Example:

    https://yahoo-mail-mcp-server.onrender.com/mcp

    Use /mcp (Streamable HTTP) for current clients. Older clients that only support SSE can use /mcp/sse.

  4. Configure OAuth Authentication

    • Click "Advanced Settings" ⚙️

    • Enter the OAuth credentials from Step 4:

      • OAuth Client ID: The value from OAUTH_CLIENT_ID environment variable

      • OAuth Client Secret: The value from OAUTH_CLIENT_SECRET environment variable

  5. Save and Test

    • Click "Add" or "Save", then "Connect"

    • A sign-in page opens: enter your username, password, and the 6-digit code from your authenticator app

    • Claude receives a token and refreshes it automatically; you only sign in again if the connection goes unused for 30 days

    • If successful, you'll see the connector active

    • You can now use Yahoo Mail tools in your conversations!

Other MCP clients (e.g. ChatGPT): add the same /mcp URL and OAuth credentials in the client's connector settings, and add the client's OAuth redirect host to OAUTH_REDIRECT_HOSTS (e.g. claude.ai,claude.com,chatgpt.com). By default only Claude's redirect hosts and localhost are allowed. This server does not support dynamic client registration, so the client must let you enter a client ID and secret.

Step 4: Using the MCP Server

Once connected, you can use these tools in your conversations:

Can you list my recent emails?

Can you read email number 5?

Can you search for emails from john@example.com?

Download the attachments from the latest email from my bank.

Draft a reply to Alice saying I'll review the budget by Friday. Then make it more formal.

Troubleshooting

Common Issues

1. "Authentication failed" error

Solution: Verify your app-specific password

  • Make sure you're using an app-specific password, not your regular Yahoo password

  • Generate a new app-specific password at https://login.yahoo.com/account/security

  • Check for typos in your .env file or Render environment variables

2. Docker build fails on Windows

Solution: Check Docker Desktop settings

  • Ensure Docker Desktop is running

  • Check that WSL2 is enabled (Settings > General > Use WSL2 based engine)

  • Verify file sharing is enabled (Settings > Resources > File Sharing)

3. Port 3000 already in use

Solution: Change the port

Windows (PowerShell):

$env:PORT=3001; npm run start:sse

Linux/macOS (Bash):

PORT=3001 npm run start:sse

Or edit .env:

PORT=3001

4. Render deployment fails

Solution: Check the logs

  • Go to your Render dashboard

  • Click on your service

  • Click "Logs" tab

  • Look for error messages

  • Common issues:

    • Missing environment variables

    • Incorrect Dockerfile path

    • Build timeout (increase build timeout in settings)

5. SSE connection drops

Solution: Render free tier limitations

  • Free tier services sleep after 15 minutes of inactivity

  • First request after sleep takes 30-60 seconds to wake up

  • Upgrade to Starter plan ($7/month) for always-on service

6. IMAP connection timeout

Solution: Check Yahoo Mail IMAP settings

  • Ensure IMAP is enabled in Yahoo Mail settings

  • Go to Yahoo Mail > Settings > More Settings > Mailboxes

  • Verify IMAP access is allowed

  • Check firewall settings aren't blocking port 993

Windows-Specific Issues

Line Ending Problems

If you see errors about line endings:

PowerShell:

# Configure git to handle line endings correctly
git config --global core.autocrlf input

# Re-clone the repository
git clone <your-repo-url>

npm Scripts Not Working

If cross-platform scripts fail:

PowerShell:

# Install cross-env globally
npm install -g cross-env

# Or run scripts directly
node server.js

Linux-Specific Issues

Permission Errors with Docker

Bash:

# Add user to docker group
sudo usermod -aG docker $USER

# Logout and login again, or run:
newgrp docker

# Test
docker ps

Environment Variables Reference

Variable

Required

Default

Description

YAHOO_EMAIL

Yes

-

Your Yahoo Mail email address

YAHOO_APP_PASSWORD

Yes

-

16-character app-specific password from Yahoo

OAUTH_CLIENT_ID

Yes (Remote)

-

OAuth 2.0 client ID for MCP server authentication (generate with openssl rand -hex 16)

OAUTH_CLIENT_SECRET

Yes (Remote)

-

OAuth 2.0 client secret for MCP server authentication (generate with openssl rand -hex 32)

TRANSPORT_MODE

No

stdio

stdio, or http for remote access (Streamable HTTP at /mcp + legacy SSE at /mcp/sse; sse is an alias)

PORT

No

3000

Port for HTTP mode (auto-set by Render)

OAUTH_ACCESS_TOKEN_TTL

No

3600

Access token lifetime in seconds

OAUTH_REFRESH_TOKEN_TTL

No

2592000

Refresh token lifetime in seconds (30 days). Each refresh token can be used once and is replaced

AUTH_USERNAME

Yes (Remote)

-

Username for the sign-in page

AUTH_PASSWORD_HASH

Yes (Remote)

-

scrypt hash of the sign-in password, from npm run setup-login (plain passwords are rejected)

AUTH_TOTP_SECRET

Recommended (Remote)

-

Base32 authenticator secret from npm run setup-login; when set, sign-in also asks for a 6-digit code

TRUST_PROXY

No

-

Express "trust proxy" setting. Set to 1 on Render so sign-in lockouts apply per client address. Don't set it when the server is reached directly, or clients could fake their address

ALLOW_CLIENT_CREDENTIALS

No

-

Set to true to allow the client_credentials grant, which skips the sign-in page. Only for trusted machine-to-machine use

ALLOW_UNAUTHENTICATED

No

-

Set to true to run HTTP mode without OAuth or a sign-in. Local testing only: anyone who can reach the server can read and change the mailbox

OAUTH_REDIRECT_HOSTS

No

claude.ai,claude.com

Hostnames allowed as OAuth redirect targets (https only; subdomains allowed; localhost is always allowed). Add other clients, e.g. chatgpt.com

DRAFTS_FOLDER

No

auto-detected

Drafts folder name. Normally detected from the server's \Drafts folder flag (Yahoo: Draft)

IMAP_IDLE_MS

No

300000

Log out of the shared IMAP connection after this many milliseconds without use

ENV_FILE

No

.env

Env file to load, relative to server.js (e.g. .env.test for a test account)

NODE_ENV

No

development

Environment: development or production

Note: The OAuth and AUTH_* settings are only required for remote deployments (Render.com); HTTP mode refuses to start without them. Local stdio mode doesn't use OAuth or a sign-in.

Available npm Scripts

Script

Description

Cross-Platform

npm start

Start server (stdio mode)

✅

npm run start:stdio

Start in stdio mode

✅

npm run start:sse

Start in SSE mode

✅

npm run dev

Development mode with auto-reload

✅

npm run docker:build

Build Docker image

✅

npm run docker:run

Run Docker container

✅

npm run docker:compose:up

Start with Docker Compose

✅

npm run docker:compose:down

Stop Docker Compose

✅

npm run docker:compose:logs

View Docker Compose logs

✅

npm run test:health

Test health endpoint

✅

npm run test:sse

Test SSE endpoint

✅

npm test

Run the offline test suite (no Yahoo logins)

✅

npm run setup-login

Create sign-in settings (username, password hash, authenticator secret)

✅

Project Structure

yahoo-mail-mcp-server/
├── server.js                 # Main server code
├── package.json             # Node.js dependencies and scripts
├── Dockerfile               # Docker build configuration
├── docker-compose.yml       # Docker Compose configuration
├── render.yaml              # Render.com deployment config
├── .env.example             # Environment variable template
├── .env                     # Your local environment variables (gitignored)
├── .dockerignore            # Files to exclude from Docker build
├── .gitignore               # Files to exclude from git
├── .gitattributes           # Git line ending configuration
├── auth.js                  # Sign-in helpers: password hashing, TOTP, login page
├── scripts/setup-login.js   # Creates the AUTH_* sign-in settings
├── test/                    # Offline tests (node --test), fake IMAP servers
└── README.md                # This file

Security Best Practices

  1. OAuth 2.0 Protection (Remote Deployments)

    • Server requires OAuth 2.0 authentication for all MCP requests

    • Uses authorization code flow with PKCE (Proof Key for Code Exchange, S256)

    • Connecting an app requires signing in on the server's own page: username, password, and (recommended) a 6-digit authenticator code (TOTP, RFC 6238)

    • The password is stored only as a scrypt hash; authenticator codes are single-use; 5 failed sign-ins from one address lock it out for 15 minutes

    • The sign-in page can't be framed (clickjacking), isn't cached, loads nothing external, and its hidden fields are signed so they can't be altered

    • The client_credentials grant (no sign-in) is off unless ALLOW_CLIENT_CREDENTIALS=true

    • Only clients with correct credentials can access your emails

    • Access tokens are signed (HMAC-SHA256, key derived from OAUTH_CLIENT_SECRET) and expire after 1 hour; clients renew them with single-use refresh tokens (30 days) without asking the user to log in again

    • Tokens need no server-side storage, so they keep working across restarts and Render sleep

    • Emergency logout: changing OAUTH_CLIENT_SECRET immediately invalidates every issued token

    • Authorization codes are random, valid for 60 seconds, single-use, and bound to their redirect_uri

    • HTTP mode refuses to start without OAuth credentials (override with ALLOW_UNAUTHENTICATED=true for local testing only)

    • Generate strong random credentials: openssl rand -hex 16 and openssl rand -hex 32

    • Store credentials securely in Render dashboard (marked as "Secret")

  2. Never commit credentials

    • .env file is gitignored

    • Always use .env.example as template

    • Set sensitive values in Render dashboard

    • Never share OAuth credentials publicly

  3. Use app-specific passwords

    • Never use your main Yahoo password

    • Generate new passwords for each service

    • Revoke unused passwords regularly

    • App passwords can be revoked without changing your main password

  4. Email management operations

    • Modification operations are reversible (soft delete, not permanent), except that update_draft permanently removes the previous version of the draft it revises

    • Deleted emails are moved to Trash folder (recoverable within 7 days for free accounts)

    • Archive, flag, and read status changes are non-destructive

    • Move operations preserve email content and metadata

    • No send operations - server cannot send emails on your behalf

  5. HTTPS in production

    • Render.com provides free SSL certificates

    • All traffic is encrypted (TLS/SSL)

    • IMAP connection uses TLS

    • OAuth tokens transmitted securely

Development Workflow

Making Changes

Windows (PowerShell):

# 1. Make your changes to server.js

# 2. Test locally
npm run dev

# 3. Test with Docker
npm run docker:compose:up

# 4. Commit and push
git add .
git commit -m "Description of changes"
git push origin main

# 5. Render automatically deploys the changes

Linux/macOS (Bash):

# 1. Make your changes to server.js

# 2. Test locally
npm run dev

# 3. Test with Docker
npm run docker:compose:up

# 4. Commit and push
git add .
git commit -m "Description of changes"
git push origin main

# 5. Render automatically deploys the changes

Viewing Logs

Local Development:

# The server logs to stderr
npm run start:sse

Docker:

npm run docker:compose:logs

Render.com:

  • Go to your service dashboard

  • Click "Logs" tab

  • Real-time logs appear here

API Endpoints

When running in HTTP mode (TRANSPORT_MODE=http), the server exposes these endpoints:

Endpoint

Method

Description

/

GET

API information and available tools

/health

GET

Health check (returns status, version, timestamp)

/mcp

POST

Streamable HTTP endpoint for MCP, stateless with JSON replies (requires OAuth token). GET/DELETE return 405

/mcp/sse

GET

Legacy Server-Sent Events endpoint for MCP (requires OAuth token)

/mcp/message

POST

Legacy SSE message endpoint (requires OAuth token)

/.well-known/oauth-protected-resource/mcp

GET

OAuth protected resource metadata for /mcp (also advertised in WWW-Authenticate on 401 responses)

/.well-known/oauth-authorization-server

GET

OAuth 2.0 server metadata (RFC 8414)

/.well-known/openid-configuration

GET

OpenID Connect discovery endpoint

/oauth/authorize

GET

OAuth 2.0 authorization endpoint

/oauth/token

POST

OAuth 2.0 token endpoint

Example Health Check Response

{
  "status": "ok",
  "service": "yahoo-mail-mcp",
  "version": "3.1.0",
  "timestamp": "2026-09-26T12:34:56.789Z"
}

Breaking Changes & Migration Guide

⚠️ v3.0.0 Breaking Changes

Version 3.0.0 introduces UID-based operations which fundamentally changes how you interact with emails. This is a breaking change that requires updating your code.

What Changed

1. Parameter Rename: sequenceNumbers → uids

All email management tools now use uids (permanent identifiers) instead of sequenceNumbers (temporary positions):

// ❌ v2.x (OLD - sequence numbers)
read_email({ sequenceNumbers: [1, 2, 3] })
delete_emails({ sequenceNumbers: [5] })

// ✅ v3.0.0 (NEW - UIDs)
read_email({ uids: [510867, 510866, 510862] })
delete_emails({ uids: [510867] })

2. Response Format: Plain Text → JSON

All tools now return structured JSON instead of plain text:

// ❌ v2.x response
"Email 1 of 10..."

// ✅ v3.0.0 response
{
  "emails": [...],
  "totalCount": 10,
  "returned": 10
}

3. New Required Workflow

You must now get UIDs from list_emails or search_emails before performing operations:

// Step 1: Get UIDs
const result = list_emails({ count: 10 });
// Returns: { emails: [{ uid: 510867, ... }, { uid: 510866, ... }] }

// Step 2: Use UIDs for operations
const uidsToDelete = [510867, 510866];
delete_emails({ uids: uidsToDelete });

Why UIDs Are Better

Sequence Numbers (v2.x):

  • ❌ Change when emails are deleted

  • ❌ Position-based (email #1, #2, #3)

  • ❌ Can become invalid between operations

  • ❌ Cause confusion and errors

UIDs (v3.0.0):

  • ✅ Permanent identifiers assigned by IMAP server

  • ✅ Never change, even when other emails are deleted

  • ✅ Always valid until email is permanently deleted

  • ✅ Reliable for batch operations

Migration Checklist

  • Update all tool calls to use uids parameter instead of sequenceNumbers

  • Update code to get UIDs from list_emails or search_emails first

  • Update code to handle JSON responses instead of plain text

  • Test batch operations to ensure all UIDs are processed (v3.0.0 fixes critical batch bug)

  • Review new features: pagination, enriched metadata, advanced search, folder support

New Features in v3.0.0

  1. Enriched Metadata: All emails include uid, size, flags, hasAttachments

  2. Pagination: list_emails supports offset and limit parameters

  3. Advanced Search: search_emails supports date ranges, sender filter, unread-only

  4. Folder Support: All tools support folder parameter (default: INBOX)

  5. list_folders: New tool to discover available IMAP folders

  6. Accurate Batch Operations: Fixed critical bug where only first UID was processed

  7. Enhanced Error Handling: Better timeout and connection error messages

MCP Tools

list_emails

List recent emails with enriched metadata (UID, size, flags, attachments) and pagination support.

Parameters:

  • count (optional): Number of emails to retrieve (default: 10, max: 50)

  • folder (optional): Folder to list from (default: 'INBOX'). Use list_folders to see available folders

  • offset (optional): Number of emails to skip for pagination (default: 0)

Response: JSON with emails array containing enriched metadata for each email:

  • uid: Permanent IMAP UID (use this for all operations)

  • sequenceNumber: Position in folder (for reference only, don't use for operations)

  • from: Sender address

  • subject: Email subject

  • date: Date in RFC 2822 format

  • size: Email size in bytes

  • flags: Array of IMAP flags (e.g., ['\\Seen'], ['\\Flagged'])

  • hasAttachments: Boolean indicating if email has attachments

Examples:

// List 20 most recent emails
list_emails({ count: 20 })

// List emails with pagination (skip first 10)
list_emails({ count: 10, offset: 10 })

// List emails from Sent folder
list_emails({ count: 15, folder: "Sent" })

read_email

Read the full content of emails using UIDs (supports batch reading).

Parameters:

  • uids (required): Array of UIDs to read (get UIDs from list_emails or search_emails)

  • folder (optional): Folder containing the emails (default: 'INBOX')

Response: Email headers, size, flags, attachment list (name, type, size), and body content, returned in the order the UIDs were requested

Examples:

// Read a single email
read_email({ uids: [510867] })

// Read multiple emails
read_email({ uids: [510867, 510866, 510862] })

// Read email from Sent folder
read_email({ uids: [510867], folder: "Sent" })

search_emails

Advanced search with filters for date ranges, sender, and unread status.

Parameters:

  • query (optional): Search term for subject or sender (can be empty for date-only searches)

  • count (optional): Number of results to return (default: 10, max: 50)

  • dateFrom (optional): Filter emails from this date onwards (ISO 8601 or RFC 2822 format)

  • dateTo (optional): Filter emails up to this date (ISO 8601 or RFC 2822 format)

  • sender (optional): Filter by specific sender email address or name

  • unreadOnly (optional): Only return unread emails (default: false)

  • folder (optional): Folder to search in (default: 'INBOX')

Response: JSON with emails array, totalMatches, returned, query, filters, and folder

Examples:

// Basic search
search_emails({ query: "invoice", count: 15 })

// Search unread emails only
search_emails({ query: "meeting", unreadOnly: true })

// Search by date range
search_emails({ dateFrom: "2025-01-01", dateTo: "2025-01-31" })

// Search by sender
search_emails({ sender: "boss@company.com" })

// Combined filters
search_emails({
  query: "report",
  sender: "team@company.com",
  dateFrom: "2025-01-15",
  unreadOnly: true
})

list_folders

Discover all available IMAP folders in your Yahoo Mail account.

Parameters: None

Response: JSON with array of folder objects containing name, path, delimiter, and children

Example:

// List all folders
list_folders()

// Example response:
// {
//   "folders": [
//     { "name": "INBOX", "path": "INBOX" },
//     { "name": "Sent", "path": "Sent" },
//     { "name": "Trash", "path": "Trash" },
//     { "name": "Archive", "path": "Archive" }
//   ]
// }

delete_emails

Move emails to Trash folder using UIDs (soft delete - emails can be recovered).

Parameters:

  • uids (required): Array of UIDs to delete (get UIDs from list_emails or search_emails)

  • folder (optional): Source folder (default: 'INBOX')

Response: Success/failure message with accurate count of processed emails

Examples:

// Delete a single email
delete_emails({ uids: [510867] })

// Delete multiple emails
delete_emails({ uids: [510867, 510866, 510862, 510856] })

// Delete from Sent folder
delete_emails({ uids: [510867], folder: "Sent" })

archive_emails

Move emails to Archive folder using UIDs for long-term storage.

Parameters:

  • uids (required): Array of UIDs to archive

  • folder (optional): Source folder (default: 'INBOX')

Response: Success/failure message with accurate count of processed emails

Examples:

// Archive a single email
archive_emails({ uids: [510867] })

// Archive multiple emails
archive_emails({ uids: [510867, 510866, 510862, 510851] })

mark_as_read

Mark emails as read using UIDs by adding the Seen flag.

Parameters:

  • uids (required): Array of UIDs to mark as read

  • folder (optional): Folder containing the emails (default: 'INBOX')

Response: Success/failure message with accurate count of processed emails

Examples:

// Mark a single email as read
mark_as_read({ uids: [510867] })

// Mark multiple emails as read
mark_as_read({ uids: [510867, 510866, 510862, 510851, 510865] })

mark_as_unread

Mark emails as unread using UIDs by removing the Seen flag.

Parameters:

  • uids (required): Array of UIDs to mark as unread

  • folder (optional): Folder containing the emails (default: 'INBOX')

Response: Success/failure message with accurate count of processed emails

Examples:

// Mark a single email as unread
mark_as_unread({ uids: [510867] })

// Mark multiple emails as unread
mark_as_unread({ uids: [510869, 510867, 510866] })

flag_emails

Flag emails as important/starred using UIDs by adding the Flagged flag.

Parameters:

  • uids (required): Array of UIDs to flag

  • folder (optional): Folder containing the emails (default: 'INBOX')

Response: Success/failure message with accurate count of processed emails

Examples:

// Flag a single email
flag_emails({ uids: [510867] })

// Flag multiple emails
flag_emails({ uids: [510851, 510865, 510864] })

unflag_emails

Remove flag/star from emails using UIDs by removing the Flagged flag.

Parameters:

  • uids (required): Array of UIDs to unflag

  • folder (optional): Folder containing the emails (default: 'INBOX')

Response: Success/failure message with accurate count of processed emails

Examples:

// Unflag a single email
unflag_emails({ uids: [510867] })

// Unflag multiple emails
unflag_emails({ uids: [510867, 510866, 510862] })

move_emails

Move emails to a specified folder using UIDs.

Parameters:

  • uids (required): Array of UIDs to move

  • folderName (required): Name of the destination folder (e.g., "Work", "Personal", "Archive")

  • sourceFolder (optional): Source folder (default: 'INBOX')

Response: Success/failure message with accurate count of processed emails

Examples:

// Move a single email to Work folder
move_emails({ uids: [510867], folderName: "Work" })

// Move multiple emails to Personal folder
move_emails({ uids: [510867, 510866, 510862], folderName: "Personal" })

// Move from Sent to Archive
move_emails({ uids: [510867], folderName: "Archive", sourceFolder: "Sent" })

Note: mark_as_read, mark_as_unread, flag_emails, unflag_emails, archive_emails, and move_emails first check which UIDs exist, then process them in one IMAP command (falling back to one at a time if that fails). delete_emails always processes one email at a time.

download_attachments

Save an email's attachments to disk. The email is opened read-only, so it isn't marked as read.

Parameters:

  • uid (required): UID of the email

  • folder (optional): Folder containing the email (default: 'INBOX')

  • filenames (optional): Only download attachments with these filenames (default: all)

  • saveDir (optional): Directory to save to (default: ~/Downloads/yahoo-attachments)

Response: Paths, types, and sizes of the saved files. Existing files are never overwritten; copies get names like report (1).pdf.

Examples:

download_attachments({ uid: 581266 })
download_attachments({ uid: 581266, filenames: ["invoice.pdf"], saveDir: "~/Documents/invoices" })

Note: In remote (HTTP) mode, files are saved on the server's disk, not your computer.

create_draft

Save a new email to the Drafts folder. Nothing is sent; review and send it from Yahoo Mail.

Parameters:

  • to (required): Array of recipient addresses, e.g. ["Jane <jane@example.com>"]

  • cc, bcc (optional): Arrays of addresses (Bcc is kept on the draft)

  • subject (required), body (required): Subject and plain-text body

  • html (optional): HTML version of the body (default: plain text only)

  • attachments (optional): Paths of local files to attach

Response: The full draft (recipients, subject, body, attachment names) and its UID

Example:

create_draft({ to: ["jane@example.com"], subject: "Lunch Friday?", body: "Hi Jane, are you free for lunch on Friday?" })

create_reply_draft

Save a reply to an existing email as a draft. Fills in the recipients (Reply-To if set, otherwise the sender), a Re: subject, and the In-Reply-To/References headers so the reply stays in the same thread. Nothing is sent.

Parameters:

  • uid (required): UID of the email being replied to

  • body (required): Reply text (written above the quoted original)

  • folder (optional): Folder containing the original (default: 'INBOX')

  • replyAll (optional): Also reply to the original's To and Cc, excluding your own address (default: false)

  • includeQuote (optional): Quote the original below the reply (default: true)

  • html (optional), attachments (optional): As in create_draft

Example:

create_reply_draft({ uid: 581098, body: "Thanks, I'll review it by Friday.", replyAll: true })

update_draft

Revise a draft. Only the fields you pass change; recipients, subject, reply threading, and attachments are otherwise kept. IMAP can't edit a message in place, so the new version is saved and the old one is removed (with UID EXPUNGE, which removes only that draft; servers without UIDPLUS move it to Trash instead).

The draft gets a new UID on every update. Always use the UID from the latest create/update result.

Parameters:

  • uid (required): UID of the draft to revise

  • to, cc, bcc (optional): Replace the address lists ([] clears Cc/Bcc)

  • subject, body (optional): Replace the subject or the whole body

  • html (optional): Replace the HTML body ("" removes it)

  • addAttachments (optional): Paths of local files to add

  • removeAttachments (optional): Filenames of attachments to remove

Example (revising from feedback):

// "Make it more formal and cc my manager"
update_draft({ uid: 395417, body: "Dear Jane, ...", cc: ["manager@example.com"] })
// → returns the full revised draft and its new UID (e.g. 395418)

Performance Considerations

Render.com Free Tier

  • Sleep after inactivity: Services sleep after 15 minutes of no requests

  • Wake-up time: First request takes 30-60 seconds

  • Monthly hours: 750 hours/month (enough for moderate use)

  • Upgrade: $7/month for Starter plan (always-on)

IMAP Performance

  • Shared connection: Tool calls reuse one IMAP login and take turns on it; the connection logs out after IMAP_IDLE_MS (default 5 minutes) without use and reconnects on the next call

  • Timeout: 30 seconds for connection and auth

  • Rate limiting: Yahoo may throttle excessive requests

  • Recommendation: Cache results on client side when possible

Cross-Platform Compatibility

This project is designed to work seamlessly on:

  • Windows 10/11 with PowerShell or Command Prompt

  • Linux (Ubuntu, Debian, Fedora, etc.)

  • macOS (Intel and Apple Silicon)

  • Docker Desktop (Windows, Mac, Linux)

  • WSL2 (Windows Subsystem for Linux)

Line Endings

  • .gitattributes ensures LF line endings in repository

  • Works correctly on Windows (CRLF) and Linux (LF)

  • Docker uses LF inside containers

Path Handling

  • All paths use forward slashes in code

  • path.join() used for cross-platform compatibility

  • Works with Windows backslashes and Unix forward slashes

Contributing

  1. Fork the repository

  2. Create a feature branch: git checkout -b feature-name

  3. Make your changes

  4. Test on both Windows and Linux (if possible)

  5. Commit: git commit -am "Add feature"

  6. Push: git push origin feature-name

  7. Create a Pull Request

License

MIT License. See the LICENSE file. Original work © jtokib; modifications © praneethpalla.

Support

Changelog

v3.1.0 (2026-09-26) - Drafts, Attachments, Streamable HTTP

New Features:

  • New tools: download_attachments, create_draft, create_reply_draft, update_draft (drafts are never sent)

  • read_email lists attachments (name, type, size) and returns emails in the requested order

  • Streamable HTTP transport at POST /mcp (stateless, JSON replies) for current MCP clients; legacy SSE kept at /mcp/sse; TRANSPORT_MODE=http

  • One shared IMAP login across tool calls, with idle logout (IMAP_IDLE_MS)

  • Bulk flag/read/archive/move run as one IMAP command after checking which UIDs exist

  • ENV_FILE, DRAFTS_FOLDER, and OAUTH_REDIRECT_HOSTS settings; .env is loaded from next to server.js

  • Offline test suite (npm test)

Bug Fixes:

  • read_email returned empty text for large emails, and returned only the first of several UIDs

  • size was always 0 in list/search/read results

  • Invalid search dates were silently ignored; they now return an error before logging in

  • Error results now set isError

  • Message bodies are buffered as bytes, so binary content isn't corrupted

Security:

  • Sign-in page for OAuth authorization: previously /oauth/authorize issued a code to anyone without asking. It now requires a username, password (scrypt hash), and optional authenticator code (TOTP), with single-use codes and a 15-minute lockout after 5 failures

  • client_credentials grant is off by default (ALLOW_CLIENT_CREDENTIALS=true to enable)

  • OAuth redirect_uri is checked by exact hostname over https. The previous substring check accepted URLs like https://evil.example/?claude.ai

  • Access tokens were never expired (despite expires_in: 3600), were stored only in memory (lost on every restart), and were built from Math.random() with the client ID in plain base64. They are now signed, expiring tokens with random IDs, plus single-use refresh tokens (refresh_token grant)

  • Authorization codes are random (crypto.randomBytes), expire after 60 seconds, and must match the original redirect_uri; a missing PKCE verifier returns an error instead of crashing

  • Client secrets are compared in constant time, and secrets containing : work with Basic auth

  • HTTP mode refuses to start without OAuth credentials

v3.0.0 (2025-01-18) - UID Migration

BREAKING CHANGES:

  • All tools now use uids parameter instead of sequenceNumbers

  • Response format changed from plain text to structured JSON

  • UIDs are permanent identifiers that don't change when emails are deleted

New Features:

  • Enriched metadata: All emails include uid, size, flags, hasAttachments

  • Pagination support: list_emails accepts offset and limit parameters

  • Advanced search filters: dateFrom, dateTo, sender, unreadOnly parameters

  • Folder support: All tools accept folder parameter (default: INBOX)

  • New tool: list_folders to discover available IMAP folders

  • Enhanced error handling: Better timeout and connection error messages with Render spindown detection

Bug Fixes:

  • CRITICAL: Fixed batch operations bug where only first UID was processed

  • All batch operations now accurately process every UID in the array

  • Success/failure messages now report exact counts of processed emails

Migration Guide:

  • Replace sequenceNumbers with uids in all tool calls

  • Get UIDs from list_emails or search_emails responses

  • Update code to handle JSON responses instead of plain text

  • See "Breaking Changes & Migration Guide" section above for details

v2.0.1 (2025-01-17)

  • Fixed: Enhanced input validation for all email operations

  • Added shared validation helper to prevent IMAP errors with invalid sequence numbers

  • Improved error messages for better debugging

v2.0.0 (2025-01-16)

  • Breaking Change: read_email now uses sequenceNumbers (array) instead of sequenceNumber (single number)

  • Added full email management with batch operations support

  • Seven new tools: delete_emails, archive_emails, mark_as_read, mark_as_unread, flag_emails, unflag_emails, move_emails

  • All modification operations support batch processing

  • Enhanced security with reversible operations (soft delete, no permanent deletion)

v1.0.0 (2025-01-11)

  • Initial release

  • Support for stdio and SSE transports

  • Docker and Docker Compose support

  • Render.com deployment configuration

  • Cross-platform compatibility (Windows/Linux)

  • Three core tools: list_emails, read_email, search_emails

Acknowledgments

FAQ

Q: Can I use this with Gmail or other email providers?

A: Currently, this server is configured for Yahoo Mail. To support other providers, change the IMAP host settings in openImapConnection() in server.js.

Q: Is this safe to use with my email account?

A: See Where Your Credentials Live for exactly who can see what in local and hosted setups. In short: The server uses app-specific passwords (not your main password) and never sends email on your behalf; it only saves drafts. Delete operations move emails to Trash (recoverable). The one permanent removal is in update_draft, which removes the previous version of the draft being revised (and only that draft).

Q: How much does it cost to run on Render?

A: The free tier provides 750 hours/month, which is enough for moderate use. For always-on service, the Starter plan is $7/month.

Q: Can I run this on other cloud platforms?

A: Yes! The Docker configuration works on any platform that supports Docker containers (AWS ECS, Google Cloud Run, Azure Container Instances, Heroku, Fly.io, etc.).

Q: Do I need to keep my computer running?

A: No! Once deployed to Render.com (or another cloud platform), the server runs independently in the cloud.

Q: How do I update the server after deployment?

A: Simply push your changes to GitHub. Render automatically detects the push and redeploys the service.

Q: Can multiple people use the same deployed server?

A: The server connects to a single Yahoo Mail account (the one configured in environment variables). Each user would need their own deployment for their own email account.

Q: What if I forget my app-specific password?

A: You can generate a new one at https://login.yahoo.com/account/security/app-passwords and update it in your Render environment variables (Settings > Environment).

Next Steps

After successful deployment:

  1. ✅ Test the health endpoint

  2. ✅ Connect to Claude.ai

  3. ✅ Try listing your emails

  4. ✅ Read a few emails

  5. ✅ Search your inbox

  6. 🎉 Enjoy your Yahoo Mail MCP server!


Happy Coding! If you have questions or issues, please open an issue on GitHub.

Available Tools

15 tools
archive_emailsC

Move emails to Archive folder using UIDs for long-term storage. UIDs are permanent identifiers.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidsYesArray of UIDs to archive
folderNoSource folder (default: INBOX)INBOX

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden of behavioral disclosure. It states the action (moving to Archive) but does not mention side effects (e.g., does it remove from INBOX? does it change read status?), required permissions, reversibility, or any limitations. The note about UIDs being permanent is useful but minimal.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences with the core action front-loaded. The second sentence adds a useful clarification about UIDs. No wasted words, though the description could have used the space to differentiate from move_emails or add usage guidance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no output schema and no annotations, the description is incomplete. It omits critical context such as whether the operation is reversible, what happens to the emails in the source folder, potential failure modes, or any prerequisites. It also fails to clarify how it differs from move_emails, which is a sibling that likely has similar behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents both parameters with descriptions (uids: 'Array of UIDs to archive'; folder: 'Source folder'). The description adds no additional parameter semantics beyond the UID permanence note, which is not strictly tied to parameter usage. Given 100% schema coverage, baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action (move/archive), resource (emails), and destination (Archive folder). It also explains UIDs are permanent identifiers, which adds specificity. However, it does not explicitly differentiate from the sibling move_emails, leaving slight ambiguity about the distinction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool versus alternatives like move_emails or delete_emails. The phrase 'for long-term storage' implies a purpose but does not state conditions or exclusions. The agent is left to infer usage without direct direction.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_draftA

Create a new email draft and save it to the Yahoo Mail Drafts folder. The email is NOT sent; the user reviews and sends it from Yahoo Mail. Returns the full draft and its UID. To revise the draft later, call update_draft with that UID.

ParametersJSON Schema
NameRequiredDescriptionDefault
ccNoOptional Cc address(es)
toYesRecipient address(es), e.g. ["Jane <jane@example.com>", "b@example.com"]
bccNoOptional Bcc address(es)
bodyYesPlain-text body of the email
htmlNoOptional HTML version of the body. If omitted, the email is plain text only.
subjectYesSubject line
attachmentsNoOptional paths of local files to attach (e.g. files saved by download_attachments)

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it discloses that the email is NOT sent and is only saved for user review, which is the critical safety-relevant behavior, and it reports the return payload ('full draft and its UID'). It omits permission/auth requirements and how invalid attachment paths are handled.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tightly written sentences; the core action, the non-send guarantee, and the follow-up routing are all front-loaded with zero filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter creation tool with no output schema, the description covers what an agent most needs: what is created, that nothing is sent, what is returned, and how to continue editing. Only auth/permission context and edge-case attachment handling are absent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema fully documents to/cc/bcc/subject/body/html/attachments. The description adds no parameter-level meaning (e.g. format expectations for the recipients array), so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Create a new email draft') plus the destination ('Yahoo Mail Drafts folder'), which is unambiguous. It differentiates itself from update_draft explicitly, though it never distinguishes itself from the sibling create_reply_draft, so sibling differentiation is only partial.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Names the follow-up alternative and the condition that selects it: 'To revise the draft later, call update_draft with that UID.' It also clarifies the non-sending workflow, telling the agent the user sends manually. It does not state when a draft is preferable to a reply draft or other creation paths.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_reply_draftA

Create a reply to an existing email (by UID) and save it as a draft. Fills in the recipients, "Re:" subject, and threading headers so the reply stays in the same conversation. The email is NOT sent. Returns the full draft and its UID; use update_draft with that UID to revise it.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesUID of the email being replied to (from list_emails or search_emails)
bodyYesPlain-text reply text (written above the quoted original)
htmlNoOptional HTML version of the reply text
folderNoFolder containing the original email (default: INBOX)INBOX
replyAllNoAlso reply to everyone in To and Cc of the original (default: false)
attachmentsNoOptional paths of local files to attach
includeQuoteNoQuote the original message below the reply (default: true)

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full load and does disclose the key behavioral trait: 'The email is NOT sent,' plus auto-populated recipients, 'Re:' subject, and threading headers, and a statement of what is returned. It omits where the draft lands and any auth/permission expectations, so it is good but not exhaustive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the action and its side-effect status, then the return value, then the follow-up tool. Every sentence earns its place with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter mutation tool with no annotations and no output schema, the description covers the essentials: what is created, what is auto-filled, that nothing is sent, what is returned (draft plus UID), and how to continue with update_draft.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter (uid, body, html, folder, replyAll, attachments, includeQuote) is already documented in the schema; baseline 3 applies. The description's mention of auto-filled recipients and threading headers adds marginal context but no syntax or format detail beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('Create a reply ... save it as a draft') and scopes it to an existing email identified by UID. This implicitly but clearly distinguishes it from the sibling create_draft (new message) and update_draft (revision). An agent can pick the right tool without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear usage context and explicitly routes the agent onward: 'use update_draft with that UID to revise it.' It does not spell out when-not-to-use (e.g., when a brand-new message is wanted, use create_draft), but the alternative for the revision path is named with its condition.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_emailsA

Move emails to Trash folder using UIDs (soft delete, recoverable). UIDs are permanent identifiers.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidsYesArray of UIDs to delete
folderNoSource folder (default: INBOX)INBOX

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses the core behavior (move to Trash, recoverable) but does not detail side effects, permissions, or what happens to related metadata. Basic transparency is present, but it could go deeper.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with zero fluff. The action and key attributes are front-loaded, making it easy to scan and understand.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter tool with no output schema and no annotations, the description covers what it does, how it works, and one critical behavioral note (recoverability). It doesn't mention the folder parameter, but the schema already covers that, so nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds value by explaining 'UIDs are permanent identifiers', giving context beyond the schema's property description. This helps an agent understand the data format and stability of UIDs.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('Move emails to Trash folder'), the method (UIDs), and the key distinction from a hard delete ('soft delete, recoverable'). It clearly identifies the resource and operation, distinguishing it from siblings like move_emails or archive_emails.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use this tool via 'soft delete, recoverable', but it does not explicitly name alternatives or specify conditions when this tool is preferred over siblings like archive_emails or move_emails. Usage is inferred rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

download_attachmentsA

Download attachments from an email (by UID) and save them to disk. Returns the saved file paths. Use read_email to see attachment names first.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidYesUID of the email containing the attachments
folderNoFolder containing the email (default: INBOX)INBOX
saveDirNoDirectory to save attachments to (default: ~/Downloads/yahoo-attachments)
filenamesNoOnly download attachments with these filenames (default: all attachments)

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must carry behavioral context. It discloses the disk-writing side effect and that it returns saved file paths, but it does not cover permissions, overwrite behavior, directory creation, or error handling for missing attachments.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences are front-loaded with the core action, then the return behavior, then the prerequisite workflow. There is no wasted wording.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is simple and the schema fully documents all four parameters. The description covers the core action, return value, and a useful prerequisite. It could be slightly richer about filesystem behavior, but it is complete enough for an agent to call correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the parameters are already well documented. The description adds little beyond the schema for uid, folder, saveDir, and filenames, though it does imply the uid identifies the target email and that filenames can be discovered via read_email.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: 'Download attachments from an email (by UID) and save them to disk.' It also identifies the relevant sibling, read_email, which helps an agent distinguish this tool from email-reading tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit workflow guidance: 'Use read_email to see attachment names first.' This tells the agent when to reach for read_email before calling this tool, though it does not state exclusions or alternative download tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

flag_emailsB

Flag emails as important/starred using UIDs. UIDs are permanent identifiers.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidsYesArray of UIDs to flag
folderNoFolder containing emails (default: INBOX)INBOX

TDQS

B3.2/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It only states that UIDs are permanent; it does not disclose that flagging mutates email state, whether the flag is reversible, what failures look like, or what the response contains.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short, front-loaded sentences with no filler. The first sentence states the action and the target; the second efficiently clarifies the permanence of UIDs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The schema fully covers the two parameters, so the main gaps are output behavior and failure semantics, which must be inferred for this mutating tool with no annotations. The low parameter count and simple action keep this gap moderate rather than severe.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% — both uids and folder already carry descriptions in the schema, so the baseline is 3. The description adds a small value-add by explaining UIDs are permanent and stable, but adds nothing about the folder parameter beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a clear verb+resource pair: 'Flag emails as important/starred using UIDs.' The 'important/starred' semantics implicitly distinguish it from siblings like mark_as_read, though the distinction is not made explicit by naming any sibling.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit when-to-use or when-not-to-use guidance is given, and no alternatives are named. The note 'UIDs are permanent identifiers' hints that UIDs are preferred over transient message numbers, which is a mild usage hint but leaves scenario selection to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_emailsA

List recent emails from a Yahoo Mail folder. Returns UIDs (permanent identifiers) and enriched metadata including size, flags, and attachment status.

ParametersJSON Schema
NameRequiredDescriptionDefault
countNoNumber of emails to retrieve (default: 10, max: 50)
folderNoFolder to list emails from (default: INBOX). Use list_folders to see available folders.INBOX
offsetNoNumber of emails to skip (for pagination, default: 0)

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the burden of behavioral disclosure. It states what is returned (UIDs and metadata) and implies a read-only 'list' operation, but does not explicitly confirm no side effects, auth requirements, or rate limits. It also does not clarify how 'recent' is determined, which is a behavioral gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence with no fluff. It front-loads the action and resource, then adds return details, with every phrase conveying necessary information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a simple list operation with no output schema or annotations, the description gives a solid overview of purpose and return contents. However, it omits an explicit read-only assurance and does not enumerate all metadata fields, which an agent might need for parsing without an output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

All three parameters (count, folder, offset) are fully documented in the schema with descriptions, defaults, and max, so the schema provides high coverage. The description adds minimal parameter meaning beyond 'recent,' which hints at recency ordering but does not elaborate on how count interacts with the list.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: 'List recent emails from a Yahoo Mail folder.' It specifies the resource (emails) and scope (folder), and names the return type (UIDs, metadata). This distinguishes it from siblings like read_email, search_emails, and list_folders.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides implied usage but no explicit when-to-use or alternative routing. The only cross-reference is in the folder parameter schema ('Use list_folders to see available folders'), not the main description. Agents must infer that listing is the appropriate tool for browsing a folder rather than searching or reading.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_foldersA

List all available IMAP folders/mailboxes in your Yahoo Mail account

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the action (list folders) but does not explicitly note that it is read-only or side-effect-free, nor does it mention any authentication or pagination details. The action implies safety, but absence of explicit disclosure leaves some room for doubt.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single, grammatically complete sentence states the purpose without redundancy or filler. Every word earns its place, and the key information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (no parameters, no output schema, no annotations), the description is largely complete for an agent to invoke it correctly. It tells the agent what the tool lists and the account scope. A minor gap is the lack of any mention of the return structure (e.g., folder names vs. full paths), but this is not critical for a low-complexity tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so schema coverage is effectively 100%. The description needs to add nothing about parameters; the baseline for no parameters is 4, and the description does not detract from it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb 'List' and names the exact resource 'all available IMAP folders/mailboxes' within the scope 'Yahoo Mail account'. It is immediately clear what the tool does and distinct from sibling tools like list_emails or search_emails.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no explicit guidance on when to use this tool versus alternatives. While it is self-evident that this is for folders and not emails, there is no mention of exclusions or conditions, leaving the agent to infer its place among siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mark_as_readB

Mark emails as read using UIDs. UIDs are permanent identifiers.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidsYesArray of UIDs to mark as read
folderNoFolder containing emails (default: INBOX)INBOX

TDQS

B3.3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It states the mutation effect but does not mention idempotency, permanence of the read state, potential side effects, permissions, or response behavior. The 'UIDs are permanent identifiers' note adds some context but does not cover operational behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with no filler. The primary action is front-loaded and the follow-up sentence provides meaningful context about UIDs. Every word contributes.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple, single-purpose mutation tool with no output schema, the description provides the essential context: the action, the resource, and the mechanism. It could be improved by noting reversibility (mark_as_unread exists) or the idempotent nature, but the low complexity means the current description is largely sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds semantic value by clarifying that UIDs are permanent identifiers, which helps agents understand that these are stable identifiers rather than transient session IDs. This goes beyond the bare schema descriptions of 'array of UIDs to mark as read' and 'folder containing emails'.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Mark emails as read') and the resource (emails), with the mechanism ('using UIDs') and a useful clarification that UIDs are permanent identifiers. While it differentiates from mark_as_unread through the word 'read', it does not explicitly call out sibling distinctions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is given about when to use this tool versus alternatives such as mark_as_unread, flag_emails, or delete_emails. The mention that UIDs are permanent identifiers implies why UIDs should be used, but there is no explicit context or exclusionary guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mark_as_unreadC

Mark emails as unread using UIDs. UIDs are permanent identifiers.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidsYesArray of UIDs to mark as unread
folderNoFolder containing emails (default: INBOX)INBOX

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It only states the basic action and that UIDs are permanent; it does not mention side effects, mutability, permissions, failure behavior, or what happens to the email state beyond marking it unread.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded with the main action, followed by a relevant clarification about UIDs. It contains no filler, though it could include a bit more useful context without becoming bloated.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter tool, the description plus schema is minimally adequate for invoking the tool. However, with no annotations and no output schema, it lacks information about expected return values, error conditions, or behavioral consequences, leaving noticeable gaps for an agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds a small amount of semantic value by noting that UIDs are permanent identifiers, which helps agents understand their stability, but it does not elaborate beyond what the schema already states.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Mark emails as unread') and the resource (emails), with a specific method (using UIDs). It is not a tautology and is distinguishable from most siblings by the 'unread' intent, though it does not explicitly differentiate itself from the closely related mark_as_read.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no guidance on when to use this tool versus alternatives like mark_as_read or read_email. It provides no use-case context, prerequisites, or exclusions, so an agent must infer when this tool is appropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

move_emailsA

Move emails to a specified folder using UIDs. UIDs are permanent identifiers. Use list_folders to see available folders.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidsYesArray of UIDs to move
folderNameYesName of the destination folder (e.g., "Work", "Personal"). Use list_folders to see available folders.
sourceFolderNoSource folder containing the emails (default: INBOX)INBOX

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the responsibility. It adds useful context that UIDs are permanent identifiers, which clarifies how to refer to emails. However, it does not disclose potential side effects such as whether the emails are removed from the source, what happens if the destination folder is invalid, or whether the operation is reversible. Some context is given, but a destructive mutation warrants more disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with no filler. The core action is front-loaded, and the additional information (UID permanence and list_folders reference) is relevant and concise. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is a mutating operation without an output schema and no annotations. The description covers the action, prerequisites, and the permanence of UIDs, but it does not mention what response the agent can expect, error conditions, or any impact on source folders. For a straightforward move operation, this is adequate but not rich; a bit more detail (e.g., success indication) would improve completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so each parameter is already documented. The description adds value by explaining that UIDs are permanent and referencing list_folders for folder names, which supplements the schema. However, it does not add deeper semantics beyond what the schema already states, so it aligns with the baseline of 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a precise action ('Move emails to a specified folder'), a specific resource (emails by UIDs), and implies the target folder. It clearly differentiates from sibling tools like delete, archive, or mark_as_read by focusing on moving to a folder, and the mention of UIDs adds specificity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a prerequisite by pointing to list_folders for available folders, which aids usage, but it does not explicitly guide when to prefer this tool over alternatives like archive_emails or delete_emails. The usage is implied rather than explicitly contrasted with siblings, so it earns a middle score.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_emailA

Read email content using UIDs (permanent identifiers). UIDs don't change when emails are deleted. Get UIDs from list_emails or search_emails.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidsYesArray of UIDs to read. UIDs are permanent identifiers from list_emails.
folderNoFolder containing the emails (default: INBOX)INBOX

TDQS

A3.7/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It states the tool reads email content, which implies no modification, but it does not explicitly confirm that it is non-destructive or mention any side effects (e.g., marking as read). It also does not describe behavior for invalid UIDs, missing folders, or rate limits. The description provides a useful fact about UID persistence but does not cover the tool's operational behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is exactly two sentences with no wasted words. It front-loads the core purpose ('Read email content using UIDs') and then adds a practical note about UID persistence and sourcing. This is concise and well-organized, earning a high score.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter tool with no output schema, the description covers the essential usage: it explains the input (UIDs), the source of that input, and the purpose. However, it does not mention error handling (e.g., invalid UIDs, non-existent folder) or the structure of returned content. Given the lack of annotations and output schema, a bit more detail about expected outcomes or failure modes would improve completeness, but the core usage is adequately covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both parameters, giving a baseline of 3. The description adds value by explaining what UIDs are (permanent identifiers) and how to obtain them, which clarifies the semantic meaning beyond the schema's basic 'Array of UIDs' description. However, it does not add details on format (e.g., integer range, array length constraints) or edge cases, so it meets the baseline without exceeding it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool reads email content using UIDs and differentiates from siblings by mentioning that UIDs are permanent and obtained from list_emails or search_emails. It specifies the resource (email content) and the action (read), which distinguishes it from listing, searching, or mutating tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives a direct usage hint ('Get UIDs from list_emails or search_emails') which establishes the source of the required input. It implies the tool is for reading full content rather than listing metadata, but it does not explicitly state when to avoid using it or compare with alternative tools beyond the UID sourcing. The context is clear enough for an agent to infer the intended use case.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_emailsA

Search emails using UIDs with advanced filters. Returns UIDs which are permanent identifiers that don't change when emails are deleted. Get UIDs from results for subsequent operations.

ParametersJSON Schema
NameRequiredDescriptionDefault
countNoNumber of results to return (default: 10, max: 50)
queryNoSearch term for subject or sender (can be empty for date-only searches)
dateToNoFilter emails up to this date (ISO 8601 or RFC 2822 format)
folderNoFolder to search in (default: INBOX). Use list_folders to see available folders.INBOX
senderNoFilter by specific sender email address or name
dateFromNoFilter emails from this date onwards (ISO 8601 or RFC 2822 format)
unreadOnlyNoOnly return unread emails (default: false)

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations exist, so the description carries the burden. It adds useful non-obvious behavior: UIDs are permanent and do not change when emails are deleted, which helps agents trust them for future calls. It does not explicitly state read-only status, though 'Search' implies it.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, all contributing value: the purpose is front-loaded, the UID permanence note is meaningful, and the chaining guidance is actionable. No filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description adequately explains the return value (UIDs) and how to use it. It covers the important chaining behavior and leaves parameter specifics to the highly detailed schema, making it sufficiently complete for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with detailed parameter descriptions, so the baseline is 3. The description adds no parameter-level meaning beyond the generic 'advanced filters' phrase, which does not enhance the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool searches emails with advanced filters and returns UIDs, which are stable identifiers. It distinguishes itself via the focus on UIDs for downstream operations, but does not explicitly contrast with sibling tools like list_emails, and the phrase 'using UIDs' is slightly awkward.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description tells agents to use this tool when they need UIDs for subsequent operations, providing a clear context. It does not explicitly state when to prefer list_emails or exclude alternatives, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

unflag_emailsB

Remove flag/star from emails using UIDs. UIDs are permanent identifiers.

ParametersJSON Schema
NameRequiredDescriptionDefault
uidsYesArray of UIDs to unflag
folderNoFolder containing emails (default: INBOX)INBOX

TDQS

B3.3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the action and notes that UIDs are permanent, but does not disclose what happens on invalid UIDs, whether the operation is reversible (unflagging can be undone by flag_emails), or any side effects. For a mutation tool with zero annotation coverage, this is a significant gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the action. The second sentence about UIDs being permanent is relevant and concise. No wasted words; the definition is efficiently structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is simple, but without annotations, an agent needs to know error behavior or return values. The description does not cover what happens if UIDs are invalid, whether it confirms the action, or if any preconditions exist (e.g., folder must exist). Given no output schema and no annotations, this is incomplete for a complete usage scenario, but acceptable for a basic mutation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already describes both parameters (uids array and folder with default). The description adds minimal extra: it clarifies that UIDs are permanent identifiers, which is useful context for why UIDs are used but not specific to parameter handling. The baseline of 3 is appropriate since the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a clear action ('Remove flag/star from emails') and the resource, with the mechanism (UIDs). It does not explicitly differentiate from sibling tools like flag_emails, but the opposite verb makes the distinction obvious. A 5 would require naming the sibling explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage: when you have UIDs and want to unflag emails. It mentions UIDs are permanent, which hints at when they are available. However, it does not give explicit guidance about when not to use this tool or mention alternatives like flag_emails. The guidance is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_draftA

Revise an existing draft in the Drafts folder. Only the fields you pass are changed; everything else (recipients, subject, reply threading, attachments) is kept. IMPORTANT: the draft gets a NEW UID on every update. Always use the UID returned by the most recent create/update call. The old version is removed. The email is NOT sent.

ParametersJSON Schema
NameRequiredDescriptionDefault
ccNoNew Cc address(es) (replaces the existing list; pass [] to clear)
toNoNew recipient address(es) (replaces the existing list)
bccNoNew Bcc address(es) (replaces the existing list; pass [] to clear)
uidYesUID of the draft to revise (from the latest create_draft, create_reply_draft, or update_draft result)
bodyNoNew plain-text body (replaces the whole body)
htmlNoNew HTML body. Pass an empty string to remove the HTML version.
subjectNoNew subject line
addAttachmentsNoPaths of local files to add as attachments
removeAttachmentsNoFilenames of existing attachments to remove

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so well: it discloses partial-update semantics, the critical UID-reassignment on every update, removal of the old version, and the fact that no email is sent. It omits permission/auth requirements and error behavior for a stale UID, which is the only notable gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, all load-bearing: purpose first, then update semantics, then the UID lifecycle warning marked IMPORTANT, then the non-send guarantee. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 9-parameter mutation tool with no annotations and no output schema, the description covers the behaviors an agent most needs: merge semantics, UID churn, and the no-send guarantee. The remaining omissions (authorization, stale UID handling) are minor but real.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds value beyond the schema by clarifying that untouched fields such as recipients, subject, reply threading, and attachments are preserved, and by warning that the uid must come from the most recent create/update result.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (revise) plus resource (existing draft in the Drafts folder), immediately distinguishing it from create_draft and create_reply_draft among its siblings. An agent can tell it is a mutation of an existing draft without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clearly establishes context: it operates on an existing draft and only touches fields you pass, implying that new drafts should go through create_draft. It does not explicitly name the alternative tools or state preconditions (e.g. draft must exist), so it stops short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 15 tool updatesv3.1.0
    • First observedarchive_emails
    • First observedcreate_draft
    • First observedcreate_reply_draft
    • First observeddelete_emails
    • First observeddownload_attachments
    • First observedflag_emails
    • First observedlist_emails
    • First observedlist_folders
    • First observedmark_as_read
    • First observedmark_as_unread
    • First observedmove_emails
    • First observedread_email
    • First observedsearch_emails
    • First observedunflag_emails
    • First observedupdate_draft

TDQS

A3.6/5.0

Scored across 15 tools

Disambiguation4/5

Tools target distinct actions on UIDs or drafts; delete/archive/move overlap slightly because delete and archive are specialized moves, but descriptions clarify intent. No two tools are indistinguishable.

Naming Consistency4/5

Most tools follow verb_noun (list_emails, create_draft), but mark_as_read/mark_as_unread use a different pattern and read_email is singular while list/search use plural. Still readable and predictable overall.

Tool Count5/5

15 tools is well-scoped for an email management server, covering message retrieval, flags, folders, attachments, and drafts without excessive surface.

Completeness3/5

Core read/manage/draft workflows are covered, but there is no send operation—agents can only create drafts—and no folder creation/deletion. This is a notable gap for an email client, though the draft-only design may be intentional.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

  • Your IMAP mailbox as an MCP server: read, search and (if you allow it) organize mail. Open source.

  • Your mailbox for MCP clients: search, read, draft, send, rules and notes. Sending is off by default.

  • Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.

  • Your agent needs a mailbox of its own — to receive, thread, draft and send, with attachments, without borrowing your personal inbox or your company's SMTP. **What you can ask for** • "Create an inbox for this agent and tell me its address." • "Read the new messages in this thread and draft a reply." • "Send this message with the attachment and wait for the response." • "Search this inbox for everything from that domain." • "Show delivery metrics and the events on this inbox." **How to use it** Point any MCP client at https://mcp.aisa.one/mail/mcp and sign in with OAuth — there is no key to create or paste. 49 tools: create and delete inboxes, list and read messages, raw message bodies, attachments, threads, drafts and draft attachments, send and reply, message search, inbox events, metrics, and list entries — reads and writes. **Why this rather than the source** A real inbox an agent owns, rather than an SMTP credential it borrows from a human. **It is also a door to the rest** The same login reaches 26 sources and 580+ operations. Find the contact elsewhere in the catalogue, then write to them from here — without adding a second server. **What it costs** Finding and inspecting an operation is free. Running one is billed per call at API prices, with no seat and no monthly minimum, and every call takes max_price_usd so an agent cannot overspend by accident. **Where else it reaches** https://mcp.aisa.one/sales/mcp finds the person to write to.

Related MCP Servers

  • F
    license
    A
    quality
    F
    maintenance
    Provides full email management for Yahoo Mail via IMAP, including listing, reading, searching, deleting, archiving, and flagging emails.
    11
    24
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables reading, searching, composing, and managing Yahoo Mail emails via IMAP with OAuth support for both local and remote MCP clients.
    28 npm
    ISC
  • F
    license
    A
    quality
    B
    maintenance
    An MCP server that provides full email management for Yahoo Mail via IMAP, including tools to list, read, search, delete, archive, flag, and move emails, with secure OAuth authentication and support for local and remote deployments.
    11
    1
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP server for Yahoo Mail over IMAP+SMTP that enables AI assistants to manage emails fully—listing, reading, searching, threading, flagging, moving, archiving, handling attachments, and sending/reply/forward/draft—using an app-specific password.
    MIT