Skip to main content
Glama
google-keep-mcp
by suckerfish

google-keep-mcp

An MCP server for Google Keep, built on gkeepapi (an unofficial, reverse-engineered client — there is no official Google Keep API for consumer accounts).

Tools

16 tools across three groups:

Notes & lists — search_notes, get_note, create_note, create_list, update_note, trash_note, restore_note, delete_note

Checklist items — add_list_item, update_list_item, delete_list_item

Labels — list_labels, create_label, delete_label, add_label_to_note, remove_label_from_note

Related MCP server: Google Keep MCP

Auth

gkeepapi authenticates with an email + master token (not your Google password, not an app password long-term). Get one:

uv run python scripts/get_master_token.py

This trades a Google App Password (requires 2FA on the account) for a master token via gpsoauth, one time. It also pins a random device ID so the server doesn't rely on the host machine's MAC address for its device identity — needed since this runs in a container, not on a fixed physical device.

Required env vars:

GOOGLE_KEEP_EMAIL=you@gmail.com
GOOGLE_KEEP_MASTER_TOKEN=...
GOOGLE_KEEP_DEVICE_ID=...

# optional: cache Keep state to disk for faster startup
GOOGLE_KEEP_STATE_PATH=./.keep_state.json

See .env.example.

Quick Start

uv sync

# Run locally (stdio)
uv run python -m google_keep_mcp.server

# Run as HTTP server
uv run python -m google_keep_mcp.server --transport streamable-http --host 0.0.0.0 --port 8080

Docker

Pre-built multi-arch images (amd64/arm64) are published to GHCR on every push to main:

docker pull ghcr.io/suckerfish/google_keep_mcp:latest

Or docker compose up using compose.yaml. Health check at GET /health.

Deployment

Runs on ampere via Komodo (stack: google-keep-mcp-ampere), registered in MetaMCP's main-namespace as google-keep-mcp (port 8082). Credentials are injected via Komodo secret variables ([[GOOGLE_KEEP_EMAIL]], [[GOOGLE_KEEP_MASTER_TOKEN]], [[GOOGLE_KEEP_DEVICE_ID]]) — never stored in the stack config or this repo. GOOGLE_KEEP_STATE_PATH points at a mounted volume so the Keep state cache survives container restarts.

Pushing to main rebuilds the image; redeploy the stack via Komodo to pick it up (auto_pull: true, but a fresh deploy still needs to be triggered — it doesn't auto-redeploy on push).

A note on stability

gkeepapi is unofficial and periodically breaks when Google changes its login flow or adds new Keep content types — see its CHANGELOG and issue tracker. If this server suddenly starts failing with LoginException or similar, it's very likely a gkeepapi compatibility issue, not something wrong in this repo. Check upstream before debugging locally.

Tech Stack

Component

Choice

MCP framework

FastMCP 2.x

Keep client

gkeepapi

Package management

uv

Available Tools

18 tools
add_label_to_noteB

Add a label to a note. Creates the label if it doesn't exist.

Args: note_id: The ID of the note. label_name: The label name to add.

Inputs: note_id (required), label_name (required). Returns: object

add_list_itemB

Add an item to an existing checklist.

Args: note_id: The ID of the list note. text: The item text. checked: Whether the item starts checked.

Inputs: text (required), note_id (required), checked. Returns: object

bulk_update_notesA

Apply the same change(s) to multiple notes in a single sync.

Does not support permanent deletion — trash notes in bulk here, then use delete_note individually once you're sure.

Args: note_ids: IDs of the notes to update. trashed: If set, trash (True) or restore (False) all notes. archived: If set, archive (True) or unarchive (False) all notes. pinned: If set, pin (True) or unpin (False) all notes. add_label: Label name to add to all notes (created if it doesn't exist). remove_label: Label name to remove from all notes.

Inputs: note_ids (required), pinned, trashed, archived, +2 more. Returns: Generic wrapper for non-object return types.

create_labelB

Create a new label.

Args: name: The label name.

Inputs: name (required). Returns: object

create_listA

Create a new checklist in Google Keep.

Args: title: List title. items: List items as objects with "text" and optional "checked" boolean. Example: [{"text": "Buy milk", "checked": false}, {"text": "Buy eggs"}] color: List color (e.g. "yellow", "blue"). pinned: Whether to pin the list. labels: Label names to apply (created if they don't exist).

Inputs: color, items, labels, pinned. Returns: object

create_noteA

Create a new text note in Google Keep.

Args: title: Note title. text: Note body text. color: Note color (e.g. "yellow", "blue", "green"). pinned: Whether to pin the note. labels: Label names to apply (created if they don't exist).

Inputs: text, color, title, labels, +1 more. Returns: object

delete_labelA

Delete a label by name. Removes it from all notes.

Args: name: The label name to delete.

Inputs: name (required). Returns: Generic wrapper for non-object return types.

delete_list_itemA

Delete an item from a checklist.

Args: note_id: The ID of the list note. item_id: The ID of the item to delete.

Inputs: item_id (required), note_id (required). Returns: object

delete_noteA

Permanently delete a note. This cannot be undone.

Args: note_id: The ID of the note to permanently delete.

Inputs: note_id (required). Returns: Generic wrapper for non-object return types.

get_attachment_urlA

Resolve a fetchable URL for one of a note's attachments (image/drawing/audio).

Makes a live network call to Google, so only call this for a specific attachment you actually need — not in a loop over search results.

Args: note_id: The ID of the note the attachment belongs to. attachment_id: The attachment's ID, from the note's "attachments" list.

Inputs: note_id (required), attachment_id (required). Returns: Generic wrapper for non-object return types.

get_noteA

Get a single note or list by its ID.

Args: note_id: The unique ID of the note.

Inputs: note_id (required). Returns: object

list_labelsA

List all labels in Google Keep.

Inputs: no named parameters. Returns: Generic wrapper for non-object return types.

remove_label_from_noteB

Remove a label from a note.

Args: note_id: The ID of the note. label_name: The label name to remove.

Inputs: note_id (required), label_name (required). Returns: object

restore_noteB

Restore a note from the trash.

Args: note_id: The ID of the note to restore.

Inputs: note_id (required). Returns: object

search_notesA

Search Google Keep notes and lists.

Args: query: Text to search in title and body (supports regex). labels: Filter by label names. color: Filter by color name (e.g. "yellow", "blue"). pinned: Filter by pinned status. archived: Filter by archived status. trashed: Include trashed notes. created_after: ISO 8601 date/datetime; only notes created at or after this. created_before: ISO 8601 date/datetime; only notes created at or before this. updated_after: ISO 8601 date/datetime; only notes updated at or after this. updated_before: ISO 8601 date/datetime; only notes updated at or before this. sort_by: Sort by "created", "updated", "edited", or "title". Unsorted (arbitrary internal order) if omitted. sort_desc: Sort descending (newest/Z-first) when sort_by is set. Default True. offset: Number of results to skip (for paging through large result sets). limit: Maximum number of results to return.

Inputs: color, limit, query, labels, +10 more. Returns: Generic wrapper for non-object return types.

trash_noteC

Move a note to the trash.

Args: note_id: The ID of the note to trash.

Inputs: note_id (required). Returns: Generic wrapper for non-object return types.

update_list_itemA

Update a list item's text or checked status.

Args: note_id: The ID of the list note. item_id: The ID of the item to update. text: New item text (omit to keep current). checked: New checked status (omit to keep current).

Inputs: item_id (required), note_id (required), text, checked. Returns: object

update_noteB

Update an existing note's properties.

Args: note_id: The ID of the note to update. title: New title (omit to keep current). text: New body text (omit to keep current; only for text notes). color: New color name. pinned: New pinned status. archived: New archived status.

Inputs: note_id (required), text, color, title, +2 more. Returns: object

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A3.7/5.0

    Scored across 18 tools

    Disambiguation5/5

    Each tool has a clearly distinct purpose covering notes, lists, labels, attachments, and bulk operations. There is no overlap or ambiguity between tools.

    Naming Consistency5/5

    All tool names follow a consistent verb_noun pattern using snake_case, such as create_note, delete_label, and search_notes. No mixing of conventions.

    Tool Count4/5

    With 18 tools, the count is slightly above the typical 3-15 range, but each tool serves a distinct function in the Google Keep domain, making the set well-scoped.

    Completeness4/5

    The tool set covers CRUD operations for notes and lists, label management, search, trash/restore, bulk updates, and attachment URLs. Minor gaps exist (e.g., no duplicate note), but core workflows are supported.

    Maintenance

    ActivityInactive
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      B
      quality
      B
      maintenance
      Enables interaction with Google Keep notes through an MCP server, allowing users to search, create, update, and delete notes via natural language commands.
      23
      957 PyPI
      113
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      A learning-oriented MCP server for managing notes, providing tools to create, list, get, update, delete, and search notes, along with resources and prompt templates.
      5 npm
      MIT