Skip to main content
Glama
systheno

Gmail MCP Gateway

by systheno

Gmail MCP Gateway

Un servidor MCP que otorga a los agentes de IA acceso completo de lectura y organización a múltiples cuentas de Gmail, sin capacidad de enviar, eliminar o borrar correos.

                     Gmail MCP Gateway

        ALLOWED                        FORBIDDEN
        ───────                        ─────────
        Search                         Send
        Read messages                  Send draft
        Read threads                   Trash
        Read attachments               Delete
        Create drafts                  Mark spam
        Edit drafts                    Gmail settings
        Archive                        Forwarding rules
        Read / unread                  Arbitrary API calls
        Labels

La garantía se aplica en el código de la aplicación, no mediante instrucciones al cliente. Un cliente MCP defectuoso, comprometido o con inyección de prompts no puede enviar correos electrónicos a través de esta puerta de enlace, porque no existe ninguna ruta de código que se lo permita.


Contenido


Related MCP server: imap-mcp

Inicio rápido

Requiere Python 3.11+. Cinco pasos, aproximadamente diez minutos, la mayor parte en la consola de Google.

1. Instalación

git clone <this-repo> gmail-mcp-gateway
cd gmail-mcp-gateway
uv sync                                  # or: python -m venv .venv && .venv/bin/pip install -e .
.venv/bin/gmail-mcp-gateway --version

Opcionalmente, colóquelo en su PATH para que los ejemplos siguientes se lean de forma más natural:

export PATH="$PWD/.venv/bin:$PATH"

2. Crear un cliente OAuth de Google

Una vez, gratuito y compartido por cada cuenta que añada posteriormente.

  1. Cree un proyecto en https://console.cloud.google.com/.

  2. APIs y Servicios → Biblioteca → active la API de Gmail.

  3. APIs y Servicios → Pantalla de consentimiento OAuthExterno, complete los campos obligatorios, añada su propia cuenta de Google en Usuarios de prueba.

  4. Publicar aplicación (aún no se necesita revisión de verificación mientras sea el único usuario). Omitir esto deja la aplicación en "Pruebas", donde Google caduca los tokens de actualización después de 7 días y tendrá que volver a autorizar cada semana.

  5. Credenciales → Crear credenciales → ID de cliente OAuth → Aplicación de escritorioDescargar JSON.

Aquí no selecciona ámbitos. La puerta de enlace solicita exactamente lo que necesita en el momento de la autorización y se niega a solicitar cualquier cosa fuera de Gmail.

3. Instalar el cliente OAuth

install -Dm600 ~/Downloads/client_secret_*.json \
  ~/.local/share/gmail-mcp-gateway/secrets/oauth_client.json

Ese es el único archivo que debe colocar manualmente. La clave de cifrado se genera automáticamente en la primera ejecución.

4. Autorizar una cuenta

gmail-mcp-gateway accounts add personal

Se abre un navegador; apruebe los permisos solicitados, dejando todas las casillas marcadas (la puerta de enlace falla de forma ruidosa en lugar de funcionar a medias si se deniega un permiso). Se almacena un token de actualización cifrado y, a partir de aquí, la puerta de enlace funciona sin supervisión.

Añada tantas como desee: cada una tiene su propio consentimiento, token de actualización, clave de cifrado, límite de velocidad y registro de auditoría:

gmail-mcp-gateway accounts add work
gmail-mcp-gateway accounts add newsletters --read-only   # Google itself refuses writes

5. Verificar

gmail-mcp-gateway health          # exit 0 = ready, 2 = something is wrong
[ok  ] directories      config=/home/you/.config/gmail-mcp-gateway ...
[ok  ] database         /home/you/.local/share/gmail-mcp-gateway/gateway.db
[ok  ] master_key       loaded
[ok  ] oauth_client     configured
[ok  ] accounts         1/1 authorized

gmail-mcp-gateway 1.0.0: healthy

Luego, apunte su cliente MCP hacia ella; consulte Conexión de un cliente MCP — o pruébela primero:

uv run python scripts/try-it.py --account personal

Variables de entorno

Para una instalación local normal no necesita ninguna. El inicio rápido anterior no establece ninguna variable de entorno. Los valores predeterminados colocan la configuración en ~/.config, los datos y secretos en ~/.local/share, y la clave de cifrado se genera sola.

Estas existen para contenedores, unidades systemd y gestores de secretos, lugares donde un archivo en disco es el mecanismo incorrecto.

Variable

¿Obligatoria?

Valor predeterminado

Propósito

GMAIL_MCP_OAUTH_CLIENT_ID

no¹

ID de cliente OAuth de Google

GMAIL_MCP_OAUTH_CLIENT_SECRET

no¹

Secreto de cliente OAuth de Google

GMAIL_MCP_MASTER_KEY

no²

generada automáticamente

Clave de cifrado de credenciales base64 de 32 bytes

GMAIL_MCP_CONFIG_DIR

no

~/.config/gmail-mcp-gateway

config.toml; nada secreto

GMAIL_MCP_DATA_DIR

no

~/.local/share/gmail-mcp-gateway

gateway.db, attachments/

GMAIL_MCP_SECRETS_DIR

no

<data>/secrets

Claves, cliente OAuth, credenciales

GMAIL_MCP_HTTP_HOST

no

127.0.0.1

Dirección de enlace HTTP

GMAIL_MCP_HTTP_PORT

no

8765

Puerto de enlace HTTP

GMAIL_MCP_HTTP_ENABLED

no

false

Habilitar transporte HTTP mediante configuración

GMAIL_MCP_ALLOW_REMOTE_BIND

no

false

Permitir enlace no local

GMAIL_MCP_LOG_LEVEL

no

INFO

DEBUGCRITICAL

¹ Alternativa a secrets/oauth_client.json. Proporcione el archivo o el par. ² Sin establecer significa que la puerta de enlace crea secrets/master.key (modo 0600) en la primera ejecución.

Las variables de entorno anulan config.toml, que a su vez anula los valores predeterminados.

Generación de cada valor

ID de cliente y secreto OAuth — del JSON que descargó en el paso 2 del inicio rápido. Para usar variables de entorno en lugar del archivo:

jq -r '.installed.client_id'     ~/Downloads/client_secret_*.json
jq -r '.installed.client_secret' ~/Downloads/client_secret_*.json

Clave maestra — 32 bytes aleatorios, en base64:

openssl rand -base64 32
# or, without openssl:
python3 -c "import base64,secrets; print(base64.b64encode(secrets.token_bytes(32)).decode())"

Esta clave descifra sus tokens de actualización almacenados. Cambiarla después de haber añadido cuentas hace que sus credenciales sean ilegibles y cada cuenta necesita accounts reauth. Realice una copia de seguridad donde guarde el directorio de datos.

Token de portador de la puerta de enlaceno es una variable de entorno. Es lo que un cliente MCP envía a través del transporte HTTP y no está relacionado con ninguna credencial de Google. La CLI lo genera y almacena solo un hash SHA-256:

gmail-mcp-gateway token create my-agent

El texto plano se imprime una vez y va en la configuración del cliente.

Uso de un archivo de entorno

La puerta de enlace no lee .env automáticamente — una herramienta de seguridad no debería absorber silenciosamente secretos del directorio en el que se inició. Copie .env.example, que documenta cada variable, y cárguelo explícitamente:

cp .env.example .env       # already covered by .gitignore
$EDITOR .env
set -a && source .env && set +a
gmail-mcp-gateway health

systemd usa EnvironmentFile=; Docker Compose usa env_file:.


Ejecución

stdio — la opción habitual

El cliente inicia la puerta de enlace como un proceso hijo y se comunica a través de tuberías. Sin puerto, sin token, sin exposición a la red. Las credenciales de Google permanecen dentro del proceso de la puerta de enlace; el cliente solo ve llamadas a herramientas.

gmail-mcp-gateway serve --transport stdio

Ejecutado manualmente, parecerá que se cuelga — eso es correcto, está esperando JSON-RPC en la entrada estándar. Normalmente, su cliente MCP lo inicia por usted.

HTTP transmisible — servicio independiente

Para un servicio de larga duración o un cliente que no puede generar procesos.

gmail-mcp-gateway token create my-agent          # once; save the printed token
gmail-mcp-gateway serve --transport http --host 127.0.0.1 --port 8765

El punto de conexión se enlaza al bucle local, requiere un token de portador y tiene protección contra reenlace de DNS activada. GET /healthz no está autenticado e informa solo de actividad.

Enlazar una dirección que no sea de bucle local requiere GMAIL_MCP_ALLOW_REMOTE_BIND=true, e incluso entonces se rechaza una dirección enrutable por Internet. Para un cliente remoto, use un túnel:

ssh -L 8765:127.0.0.1:8765 gateway-host

systemd

deploy/gmail-mcp-gateway.service se ejecuta como un usuario de sistema dedicado en un entorno protegido reforzado — ProtectSystem=strict, CapabilityBoundingSet vacío, filtro seccomp, NoExecPaths sobre el directorio de datos. Los pasos de instalación están en el encabezado de la unidad. Autorice las cuentas una vez, de forma interactiva, como el usuario del servicio antes de iniciarlo.

Docker

deploy/Dockerfile y deploy/docker-compose.yml se ejecutan como no root y de solo lectura, con todas las capacidades eliminadas, y el puerto publicado solo en el bucle local. La imagen no contiene credenciales; estas residen en el volumen /secrets.

docker compose -f deploy/docker-compose.yml up -d

La secuencia de autorización única — colocar el cliente OAuth, ejecutar el flujo de consentimiento con el puerto de redirección publicado, generar un token — está en los comentarios del encabezado del archivo compose.


Conexión de un cliente MCP

stdio

{
  "mcpServers": {
    "gmail": {
      "command": "/absolute/path/to/gmail-mcp-gateway/.venv/bin/gmail-mcp-gateway",
      "args": ["serve", "--transport", "stdio"]
    }
  }
}

Claude Code:

claude mcp add gmail -- /absolute/path/to/.venv/bin/gmail-mcp-gateway serve --transport stdio

HTTP

{
  "mcpServers": {
    "gmail": {
      "type": "http",
      "url": "http://127.0.0.1:8765/mcp",
      "headers": { "Authorization": "Bearer <token from `token create`>" }
    }
  }
}

Los clientes nunca montan ni acceden de otro modo a los archivos de credenciales de Google. Con stdio, el cliente se comunica a través de una tubería; con HTTP, posee un token de puerta de enlace no relacionado con ninguna credencial de Google.


Referencia de herramientas

Toda herramienta toma un alias de account — no hay cuenta predeterminada. Las herramientas de mutación aceptan un client_request_id opcional para la idempotencia: repetir una llamada con el mismo id y argumentos devuelve el primer resultado en lugar de actuar dos veces.

Herramienta

Qué hace

accounts_list

Alias, direcciones, estado, capacidades concedidas. Sin credenciales.

accounts_status

Verificación de autorización en vivo por cuenta, más totales del buzón.

gmail_search

Sintaxis de búsqueda de Gmail; detail de ids, metadata o full; paginado.

gmail_get_message

Un mensaje: remitente, para, cc, cco, asunto, marca de tiempo, etiquetas, estado de lectura, cuerpo, inventario de archivos adjuntos.

gmail_get_thread

Una conversación completa en orden, con participantes.

gmail_attachments_list

Inventario de archivos adjuntos. No descarga nada.

gmail_attachments_get

Obtener bytes: base64 en línea cuando es pequeño; de lo contrario, se escribe en el directorio propio de la puerta de enlace.

gmail_labels_list

Todas las etiquetas con recuentos, y si la puerta de enlace modificará cada una.

gmail_labels_add

Aplicar etiquetas por id o nombre. Rechaza TRASH y SPAM.

gmail_labels_remove

Eliminar etiquetas por id o nombre. Rechaza TRASH y SPAM.

gmail_archive

Eliminar INBOX. El correo permanece en Todos; reversible.

gmail_mark_read

Eliminar UNREAD.

gmail_mark_unread

Añadir UNREAD.

gmail_drafts_list

Borradores guardados con destinatarios, asunto, fragmento.

gmail_drafts_get

Un borrador completo.

gmail_drafts_create

Nuevo borrador de texto plano. Guardado, nunca enviado.

gmail_drafts_reply

Borrador de respuesta en un hilo existente, con In-Reply-To, References, asunto y threadId correctos.

gmail_drafts_update

Editar un borrador; los campos omitidos conservan sus valores, el hilo se preserva.

Las mutaciones funcionan en mensajes o hilos individuales y en lotes (límite predeterminado de 100 ids). Las etiquetas pueden darse como ids (Label_7) o nombres para mostrar (Receipts).

La lectura y la escritura se tratan de forma asimétrica donde es importante: gmail_search filtrará felizmente por TRASH o establecerá include_spam_trash, porque inspeccionar lo que ya está ahí es una lectura. Se rechaza la aplicación de esas etiquetas, porque eso movería el correo a la Papelera o lo reportaría como spam.

Errores

Los fallos se devuelven como errores de herramienta MCP con isError: true y una carga útil estructurada tanto en el bloque de texto como en el contenido estructurado:

{"error": {
  "code": "forbidden_label",
  "message": "refusing to add label 'TRASH': moving messages to Trash is a forbidden capability of this gateway",
  "retryable": false
}}

Los códigos incluyen invalid_input, unknown_account, not_found, too_large, batch_too_large, rate_limited, forbidden_operation, forbidden_label, account_read_only, needs_reauth, upstream_rate_limited, upstream_unavailable, network_error, timeout e internal_error. Las excepciones internas se registran en el lado del servidor y se reportan como un internal_error simple — los clientes nunca reciben un traceback ni una ruta interna.


Administración

gmail-mcp-gateway accounts list
gmail-mcp-gateway accounts status               # live Gmail check per account
gmail-mcp-gateway accounts auth <alias>
gmail-mcp-gateway accounts reauth <alias>       # after a revoked or expired grant
gmail-mcp-gateway accounts remove <alias> --yes # revokes at Google, deletes locally

gmail-mcp-gateway token create <name>
gmail-mcp-gateway token list
gmail-mcp-gateway token revoke <name>

gmail-mcp-gateway audit --limit 50              # recent state-changing operations
gmail-mcp-gateway audit --account work --since-hours 24
gmail-mcp-gateway audit --outcome denied --json

gmail-mcp-gateway prune                         # expired audit rows, dedup keys, attachments
gmail-mcp-gateway health --json

En un host sin interfaz gráfica, autoriza con el puerto de redirección reenviado:

# on the server
gmail-mcp-gateway accounts add work --no-browser --port 8899
# on your laptop
ssh -L 8899:127.0.0.1:8899 server
# then open the printed URL locally

El registro de auditoría registra cuenta, marca de tiempo, operación, identificadores afectados, resultado, código de error, duración y principal solicitante — tanto para aciertos, fallos como denegaciones. Nunca registra tokens, cuerpos de mensajes, asuntos ni contenidos de adjuntos. La administración es solo por CLI: un cliente MCP comprometido no puede agregar una cuenta, iniciar un flujo de consentimiento, emitir un token ni leer el registro de auditoría.

Estructura de directorios

La configuración, los datos y los secretos están separados y se pueden sobrescribir individualmente, de modo que cada uno puede tener un almacén de respaldo diferente:

Rol

Variable

Valor por defecto

Contenido

Config

GMAIL_MCP_CONFIG_DIR

~/.config/gmail-mcp-gateway

config.toml — nada secreto

Datos

GMAIL_MCP_DATA_DIR

~/.local/share/gmail-mcp-gateway

gateway.db, attachments/

Secretos

GMAIL_MCP_SECRETS_DIR

<data>/secrets

master.key, oauth_client.json, credentials/, gateway_tokens.json

config.toml es opcional; consulta deploy/config.example.toml para conocer todas las claves — límites de lote, tamaños de página, presupuestos de cuerpo y adjuntos, límites de tasa, política de reintentos y ventana de idempotencia — con sus valores predeterminados.


Cómo se aplica el límite

Cuatro capas independientes. Cada una por sí sola bloquearía un envío; las cuatro deben fallar para que un mensaje salga.

1. La superficie de herramientas. Existen dieciocho herramientas. No hay gmail_send, ni gmail_trash, ni gmail_raw_request, ni ninguna herramienta que acepte una URL, ruta, método HTTP o nombre de endpoint. Un proxy genérico de Gmail no es algo que el cliente pueda alcanzar porque no es algo que se haya escrito. mcpsrv/server.py

2. La lista blanca de endpoints. Cada solicitud HTTP a Gmail debe nombrar una de las catorce constantes Endpoint. users.messages.send, users.drafts.send, users.messages.trash, users.messages.delete y todo lo que está bajo users.settings simplemente están ausentes. Los parámetros de ruta se validan contra un patrón de id estricto y se codifican en porcentaje con un conjunto seguro vacío, por lo que ningún valor puede introducir un / y alcanzar un endpoint diferente. Una lista negra vuelve a verificar el método y la ruta resueltos inmediatamente antes de que la solicitud salga, independientemente de cómo se haya construido. No se pueden emitir DELETE ni PATCH. gmail/allowlist.py

3. La política de etiquetas. Esto cierra la puerta trasera que deja abierta la lista blanca. users.messages.modify está permitido — es como funcionan el archivado y el estado de lectura — pero Gmail trata TRASH y SPAM como etiquetas ordinarias, por lo que aplicar una de ellas envía un mensaje a la papelera o lo reporta como spam. Cada id de etiqueta en una mutación se verifica, en ambas direcciones, sin distinción de mayúsculas y minúsculas, y el cuerpo de la solicitud ensamblado se vuelve a verificar antes de la transmisión. gmail/labels.py

4. El alcance de OAuth. Las cuentas se autorizan con gmail.modify y nada más. Ese alcance no puede eliminar permanentemente un mensaje (messages.delete requiere https://mail.google.com/) y no puede tocar ninguna configuración de Gmail, por lo que las reglas de reenvío, los filtros, la configuración de POP/IMAP y la eliminación permanente son imposibles en la capa de autorización de Google, no solo bloqueados aquí. Google no publica ningún alcance que otorgue la creación de borradores sin envío, por lo que el envío está bloqueado por las capas 1–2. Las cuentas agregadas con --read-only obtienen gmail.readonly, y el propio Google rechaza entonces cualquier escritura.


Modelo de seguridad

El contenido del correo electrónico no es de confianza. Los cuerpos, asuntos, nombres de remitentes y nombres de archivos adjuntos son escritos por terceros y pueden contener instrucciones dirigidas al modelo que los lee. La puerta de enlace marca cada resultado de lectura como content_is_untrusted: true, y las instrucciones del servidor le indican al cliente que trate el correo electrónico como datos, no como directivas. De manera más útil, las capacidades que las instrucciones inyectadas solicitarían no existen.

El HTML nunca se ejecuta y nunca se devuelve como marcado. <script>, <style>, <iframe> y elementos similares se descartan junto con su contenido; todas las demás etiquetas se eliminan. El resultado es texto plano.

Los caracteres Unicode invisibles se eliminan. Los caracteres de ancho cero, las anulaciones bidireccionales y las etiquetas Unicode permiten que un atacante muestre una cosa a un humano mientras que un LLM lee otra. Se eliminan y el recuento se informa como removed_hidden_characters.

Los archivos adjuntos se almacenan, nunca se abren. La puerta de enlace no analiza, renderiza ni ejecuta el contenido de los archivos adjuntos. Un cliente puede sugerir un nombre de archivo pero nunca una ruta: el destino es siempre <attachments_dir>/<account>/<message_id>/<sanitized-name>, resuelto y verificado para contención, escrito con O_NOFOLLOW en modo 0600.

Las credenciales nunca llegan al cliente. Los tokens de actualización, los tokens de acceso y el secreto del cliente OAuth existen solo dentro del proceso de la puerta de enlace. La credencial de cada cuenta se sella con AES-256-GCM bajo una clave derivada por cuenta (HKDF-SHA256(master, "…account:<id>")), con el id de la cuenta como datos asociados — por lo que la clave de una cuenta no abre la de otra, y un archivo de credencial movido entre cuentas falla al descifrarse. Los archivos son 0600 en un directorio 0700; la puerta de enlace se niega a leer una clave legible por el grupo o por otros.

Alcance honesto: el cifrado en reposo protege contra copias de seguridad, copias sueltas e imágenes de disco. No defiende contra un atacante que ya está ejecutando código como el usuario de la puerta de enlace — ese atacante puede leer la clave maestra. Los permisos del sistema de archivos siguen siendo el límite principal.

Los registros no pueden filtrar secretos. Cada registro de log pasa por un filtro de redacción que reescribe cualquier cosa con forma de token de acceso o actualización de Google, secreto de cliente, encabezado de portador, JWT o campo con nombre de credencial — en el mensaje, los argumentos y el texto de la excepción. Bajo stdio, los logs van a stderr porque stdout es el cable MCP.

Las entradas se validan. Los destinatarios de los borradores deben ser direcciones simples que coincidan con un patrón estricto; cualquier CR, LF o NUL en un valor de encabezado se rechaza como intento de inyección de encabezado. Los borradores se ensamblan a partir de campos tipados — la puerta de enlace nunca acepta RFC 5322 sin procesar de un cliente. Los lotes, tamaños de página, longitudes de cuerpo, tamaños de adjuntos y recuentos de destinatarios están limitados, y un bucket de tokens por cuenta falla rápidamente con una sugerencia retry_after_seconds en lugar de poner en cola.

Contra lo que esto no protege

  • Un operador que pueda ejecutar código como el usuario de la puerta de enlace.

  • Un cliente que use legítimamente las capacidades permitidas de manera incorrecta — archivado masivo, por ejemplo, o escribir un borrador engañoso. El archivado y el etiquetado son reversibles y están auditados; los borradores aún requieren que un humano los envíe.

  • Un compromiso del lado de Google o una configuración maliciosa del cliente OAuth.

  • La interceptación de tráfico si expones el transporte HTTP sin TLS. Mantenlo en bucle local o coloca un proxy de terminación TLS al frente.


Fiabilidad

  • Actualización de token: automática, con un bloqueo por cuenta para que las llamadas concurrentes se actualicen una vez. Un 401 desencadena exactamente una actualización y reintento.

  • Fallo de actualización: invalid_grant marca la cuenta como needs_reauth y devuelve un error estructurado que nombra el comando CLI para solucionarlo.

  • Límites de tasa y 5xx: retroceso exponencial con jitter completo, respetando Retry-After, hasta max_attempts.

  • Fallos de red y tiempos de espera: se reintentan, luego se informan como network_error o timeout sin detalles internos.

  • Paginación: next_page_token se devuelve al cliente, por lo que no hay estado de cursor en el servidor.

  • Solicitudes duplicadas: client_request_id suprime repeticiones durante 24 horas. Las repeticiones concurrentes se serializan dentro del proceso; reutilizar un id con argumentos diferentes es un error, no una respuesta incorrecta silenciosa.

  • Contrapresión: las llamadas a Gmail comparten un semáforo de concurrencia configurable, y cada cuenta tiene un bucket de tokens independiente. Por lo tanto, una búsqueda grande o una cuenta ocupada no pueden crear una concurrencia ascendente ilimitada.

Topología de escalado e implementación

Ejecuta un proceso de puerta de enlace para un directorio de datos y secretos determinado. El estado de SQLite, los archivos de credenciales, los bloqueos de actualización de tokens y la coordinación de idempotencia en curso son intencionalmente locales; apuntar múltiples réplicas al mismo volumen no proporciona una operación activo-activo segura.

Para una instalación más grande, divide las cuentas en instancias de puerta de enlace independientes, cada una con su propia configuración, datos, secretos, tokens de portador y puerto de bucle local. Esto mantiene los fallos, límites de tasa, pistas de auditoría y credenciales aislados, al tiempo que permite que cada instancia atienda a clientes concurrentes. Aumenta limits.max_concurrency solo después de observar el uso de la cuota de Gmail y la capacidad del host; el valor predeterminado de 8 es conservador. Coloca una capa de enrutamiento autenticada con TLS al frente si los clientes necesitan una dirección de red compartida, y enruta cada alias de cuenta a su propia instancia.

Las réplicas activo-activo para la misma cuenta requerirían reemplazar SQLite y el estado local de credenciales/idempotencia con almacenes externos coordinados. Eso está fuera del modelo de seguridad actual de esta puerta de enlace; no la escales simplemente agregando workers o compartiendo su volumen.


Pruebas

uv sync --all-extras
uv run pytest -q                                    # 334 tests, no Google account needed
uv run pytest tests/test_security_boundary.py -v    # just the guarantee

test_security_boundary.py impulsa cada operación compatible a través de un Gmail simulado que falla si se solicita una URL prohibida, luego intenta enviar a la papelera, a spam y enviar por cada ruta disponible.

Una vez que una cuenta está autorizada, pruébala contra un buzón real. El script se conecta a través de stdio exactamente como lo haría un cliente MCP, ejecuta un recorrido de solo lectura, luego confirma que las operaciones prohibidas son rechazadas:

uv run python scripts/try-it.py --account personal
uv run python scripts/try-it.py --account personal --draft    # also drafts a reply
uv run python scripts/try-it.py --account personal --archive  # archive round trip

Solo lectura a menos que pases un indicador de mutación, y cada mutación que realiza es reversible. El borrador que crea debe ser eliminado por ti — la puerta de enlace no puede.

Para hacer clic de forma interactiva:

npx @modelcontextprotocol/inspector .venv/bin/gmail-mcp-gateway serve --transport stdio

Diseño

src/gmail_mcp_gateway/
├── mcpsrv/server.py      the tool surface — the complete client-facing API
├── mcpsrv/http.py        Streamable HTTP transport, bearer auth, bind safety
├── service.py            the supported operations, and nothing else
├── gmail/allowlist.py    the endpoint allowlist  ← security boundary
├── gmail/labels.py       label policy (blocks TRASH/SPAM)  ← security boundary
├── gmail/client.py       the only code that talks to Gmail
├── gmail/parse.py        MIME → structured data, sanitization
├── gmail/compose.py      draft assembly from typed fields
├── security/             validation, rate limiting, path confinement
├── auth/oauth.py         OAuth 2.0 + PKCE, refresh, revoke
├── accounts.py           account registry
├── crypto.py             envelope encryption for credentials
├── audit.py              audit log
└── cli.py                administration

Agregar una operación compatible significa: un Endpoint en allowlist.py, un método en service.py, una herramienta en mcpsrv/server.py, una entrada en EXPOSED_TOOLS y pruebas. EXPOSED_TOOLS y FORBIDDEN_TOOLS se verifican contra el servidor en ejecución, por lo que agregar una herramienta sin declararla — o agregar una prohibida — hace que la suite falle. Mantén la puerta de enlace centrada en Gmail; un producto diferente de Google pertenece a un servicio MCP separado, no a ámbitos más amplios aquí.


Solución de problemas

no OAuth client configured — paso 3 de la guía de inicio rápido. Coloca secrets/oauth_client.json (modo 0600) o establece GMAIL_MCP_OAUTH_CLIENT_ID y GMAIL_MCP_OAUTH_CLIENT_SECRET.

Google did not return a refresh token — ya has autorizado esta aplicación antes. Elimina su acceso en https://myaccount.google.com/permissions y ejecuta accounts auth <alias> de nuevo.

consent screen did not grant every required permission — una casilla de permiso no estaba marcada. Reautoriza y déjalas todas marcadas. La puerta de enlace falla aquí a propósito en lugar de dejar una cuenta que funcione a medias.

La cuenta pasa a needs_reauth cada semana — la aplicación OAuth todavía está en "Pruebas", donde Google caduca los tokens de actualización después de 7 días. Publícala (paso 2.4 de la guía de inicio rápido).

stored credential failed authenticationGMAIL_MCP_MASTER_KEY cambió, o el archivo de clave fue reemplazado. Restaura la clave original, o ejecuta accounts reauth <alias> para cada cuenta.

<file> is accessible to other users — la puerta de enlace se niega a leer un secreto legible por el grupo o por otros. Ejecuta chmod 600 en el archivo que nombra.

refusing to bind …: it is not a loopback address — intencional. Vincula 127.0.0.1 y usa un túnel SSH, o establece GMAIL_MCP_ALLOW_REMOTE_BIND=true si realmente es una interfaz de confianza privada. Las direcciones enrutables por Internet son rechazadas independientemente.

serve --transport stdio parece colgado — correcto; está esperando JSON-RPC en stdin. Deja que tu cliente MCP lo inicie, o usa scripts/try-it.py.

Algo ha cambiado el buzón y quiero saber quégmail-mcp-gateway audit --limit 50. Cada cambio de estado está ahí, incluidos los rechazos.

Licencia

MIT

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    -
    quality
    A
    maintenance
    An open-source MCP server that provides AI agents with secure access to read, search, and manage emails via Microsoft 365 and Gmail. It features security-first defaults like recipient allowlists and markdown content conversion to facilitate safe agent interaction with mailboxes.
    4
    Apache 2.0
  • A
    license
    -
    quality
    B
    maintenance
    Read-only MCP server for IMAP email access, enabling AI agents to read, search, and monitor email without sending or deleting messages.
    47
    MIT
  • A
    license
    C
    quality
    C
    maintenance
    Multi-account Gmail MCP server that lets assistants scan inbox, read threads, draft and send emails only after human approval, and manage follow-up reminders.
    42
    68
    MIT

View all related MCP servers

Related MCP Connectors

  • Hosted email MCP for AI agents with inboxes, send/receive, memory, recovery, and credits.

  • Shipmail MCP server for AI agent custom-domain email inboxes with REST API and webhooks.

  • Read, search, send, organize, draft and schedule email across your inboxes from any MCP client.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systheno/gmail-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server