feat(gmail): add get_gmail_label_stats tool for unread/total message counts#698
feat(gmail): add get_gmail_label_stats tool for unread/total message counts#698robelmes wants to merge 1 commit into
Conversation
…loses #1) Add a new MCP tool that returns message and thread counts for a Gmail label using the labels.get endpoint — much faster than paginating through search results to count unread messages. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
📝 WalkthroughWalkthroughA new MCP tool function Changes
Sequence DiagramsequenceDiagram
participant Client
participant MCP as MCP Server
participant Gmail as Gmail API
Client->>MCP: Call get_gmail_label_stats(label_id)
activate MCP
MCP->>MCP: Verify read-only access & auth
MCP->>Gmail: users().labels().get(id=label_id).execute()
activate Gmail
Gmail-->>MCP: Label metadata + counts
deactivate Gmail
MCP->>MCP: Extract & format stats
MCP-->>Client: Formatted label statistics
deactivate MCP
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
tests/gmail/test_get_gmail_label_stats.py (1)
1-122: Test coverage looks good.Four scenarios (default INBOX, custom label, zero counts, missing fields) cover the meaningful branches of the formatter. Mock wiring via shared
return_valuechains correctly models theservice.users().labels().get(...).execute()call, and_unwrapappropriately bypasses the FastMCP/decorator layers.Minor optional suggestions (non-blocking):
- Line 51/78:
assert_called_once_with(userId="me", id=...)is good; consider additionally asserting.executewas awaited/called once to catch regressions where someone re-invokes the builder chain.test_inbox_defaultdoes not assert the labeltype("system") is rendered in the header, whereastest_custom_label_iddoes. Adding a symmetric check would tighten coverage.- The
sys.path.insertat line 7 works but is brittle; if this repo configurespytestroots viaconftest.py/pyproject.toml, prefer relying on that instead.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/gmail/test_get_gmail_label_stats.py` around lines 1 - 122, Add assertions to verify the final execute call and the label type rendering: in test_inbox_default and test_custom_label_id, after calling fn(...) assert that service.users().labels().get().execute was called once (to catch broken builder invocation) and in test_inbox_default also assert the label "system" appears in result (symmetry with test_custom_label_id which checks "user"); locate these in the tests referencing _mock_service, test_inbox_default, and test_custom_label_id and add the two assertions accordingly.gmail/gmail_tools.py (1)
2576-2630: LGTM — clean, idiomatic addition.The tool follows the established pattern in this file: decorator order matches other read-only tools,
asyncio.to_threadis correctly passed the bound.executemethod reference, the least-privilegegmail_readscope is used, and missing optional counters safely default to0viaresponse.get(..., 0). Output format is consistent withlist_gmail_labels.One optional nit: for very large mailboxes the raw counts (e.g.
123456) may be harder to read. Consider formatting with thousands separators (f"{messages_total:,}") for nicer display. Non-blocking.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@gmail/gmail_tools.py` around lines 2576 - 2630, The numeric counters in get_gmail_label_stats (messages_total, messages_unread, threads_total, threads_unread) should be displayed with thousands separators for readability; update the formatted strings in the lines list (the f-strings that currently embed messages_total, messages_unread, threads_total, threads_unread) to use comma-formatting (e.g. f"{messages_total:,}") so large counts render with separators.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@gmail/gmail_tools.py`:
- Around line 2576-2630: The numeric counters in get_gmail_label_stats
(messages_total, messages_unread, threads_total, threads_unread) should be
displayed with thousands separators for readability; update the formatted
strings in the lines list (the f-strings that currently embed messages_total,
messages_unread, threads_total, threads_unread) to use comma-formatting (e.g.
f"{messages_total:,}") so large counts render with separators.
In `@tests/gmail/test_get_gmail_label_stats.py`:
- Around line 1-122: Add assertions to verify the final execute call and the
label type rendering: in test_inbox_default and test_custom_label_id, after
calling fn(...) assert that service.users().labels().get().execute was called
once (to catch broken builder invocation) and in test_inbox_default also assert
the label "system" appears in result (symmetry with test_custom_label_id which
checks "user"); locate these in the tests referencing _mock_service,
test_inbox_default, and test_custom_label_id and add the two assertions
accordingly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a49a2cd7-b69c-4f31-af72-ae59ad0ae399
📒 Files selected for processing (2)
gmail/gmail_tools.pytests/gmail/test_get_gmail_label_stats.py
Summary
Add a
get_gmail_label_statsMCP tool that returns message and thread counts for a Gmail label using thelabels.getendpoint.Motivation
Currently, the only way to get unread message counts is to paginate through
search_gmail_messageswithis:unread— which is slow and token-heavy for accounts with many messages. The Gmail API'slabels.getendpoint returnsmessagesTotal,messagesUnread,threadsTotal, andthreadsUnreadin a single API call.What changed
get_gmail_label_statstool (placed afterlist_gmail_labels). Accepts an optionallabel_idparameter (defaults toINBOX), callsservice.users().labels().get(), and returns formatted stats.Implementation details
@server.tool()/@handle_http_errors/@require_google_servicegmail_readscope (read-only, no extra permissions needed)Example output
Gmail API Reference
Summary by CodeRabbit
New Features
Tests