A big community release: Gmail now composes, replies and forwards exactly like Gmail web, Sheets gains borders, dropdowns, merges and tab styling, and HTTP deployments get a Host allowlist, a configurable OAuth consent mode and an honest failure for broken streamed downloads. Welcome to seven new contributors!
Gmail
- gmail: Sends, drafts, replies and forwards are now built the way Gmail web builds them (MIME layout, quoted reply trail, forwarded-message block), with a new
directionparameter (auto/ltr/rtl) for right-to-left mail. feat(gmail): forward messages the way Gmail web does by @seidnerj in #1238 - gmail:
from_emailis checked against your send-as identities, so an unknown alias fails with the accepted addresses listed instead of Gmail quietly sending from your default address. feat(gmail): reject a send-as alias Gmail would silently discard by @cfdude in #1075 - gmail: An HTML body that arrives entity-escaped (
<div>...) is rejected before sending, so recipients never get raw markup. fix(gmail): reject an entity-escaped HTML body before sending by @seidnerj in #1233 - gmail:
batch_modify_gmail_message_labelsacceptsthread_idsto relabel whole conversations at once. feat(gmail): thread_ids in batch_modify_gmail_message_labels by @rylos in #1177 - gmail: Inline images get an
X-Attachment-Idmatching theirContent-ID, so they render inline instead of as attachments. fix(gmail): give inline images an X-Attachment-Id matching their Content-ID by @DannyGelf in #1279
Sheets
- gsheets:
format_sheet_rangecan merge and unmerge cells. feat(gsheets): add cell merge and unmerge capabilities to format_sheet_range by @antoine2711 in #1175 - gsheets:
format_sheet_rangedraws borders and adds dropdown validation, andmanage_sheet_tabgains astyleaction for tab color and gridlines. feat(gsheets): borders and dropdowns in format_sheet_range, style action in manage_sheet_tab by @2000game in #1215
Docs
- gdocs: Markdown pipe tables become real Google Docs tables in
populate_from_markdowninstead of a paragraph of literal pipes. feat(docs): render GFM tables natively in populate_from_markdown by @juliandickie in #929 - gdocs: Markdown body text inserted after a heading no longer inherits the heading style. fix(gdocs): emit NORMAL_TEXT reset for body paragraphs + spacers in markdown_to_docs_requests by @johntrandall in #850
- gdocs:
debug_table_structuretakestab_id, and table operations raise on an unknown tab rather than silently writing into the first one. fix(gdocs): tab_id for debug_table_structure, no silent first-tab fallback in table ops by @taylorwilsdon in #1274 - gdocs: Clearer
inspect_doc_structureguidance on the final body range. docs(gdocs): clarify the body-final range note in inspect_doc_structure by @kryan007 in #1100 - gdocs:
create_docnow says its content is plain text and points toimport_to_google_docfor Markdown. docs(create_doc): note content is plain text; point to import_to_google_doc for Markdown by @imparpaulo01 in #935 - skill: Documents the snapshot-by-copy pattern for rolling back a Google Doc. docs(skill): document the snapshot-by-copy pattern for Google Docs rollback by @johntrandall in #1277
Calendar & Drive
- gcalendar:
list_calendarsshows each calendar's time zone, so agents can pick the right zone formanage_event. feat(calendar): include each calendar's time zone in list_calendars by @socromentoRep in #1253 - gcalendar: Compact
get_eventsoutput marks cancelled events, so a deleted event no longer looks live. fix(gcalendar): show cancelled status in compact get_events output by @taylorwilsdon in #1273 - gdrive:
copy_drive_filecan carry comments over withcopy_comments. Pass copyComments through copy_drive_file by @Omarinho12345 in #1246 - gdrive: Clarifies that the
file_nameextension drives source-format detection. docs(drive): clarify file_name extension drives source-format detection by @axsaucedo in #1050
Auth, security & server
- core: New opt-in
WORKSPACE_MCP_ALLOWED_HOSTSreturns 403 for requests to a non-allowlistedHost, closing a DNS-rebinding path for same-origin GETs. fix(core): reject same-origin browser fetches to a non-allowlisted Host by @seidnerj in #1232 - auth: New
WORKSPACE_MCP_OAUTH_PROXY_REQUIRE_CONSENT=remembershows the OAuth proxy consent screen once per browser for each client instead of on every authorization (defaultalways). feat(auth): expose the OAuth proxy consent mode as an env var by @DrFaust92 in #1088 - auth:
--permissionssupports union syntax likegmail:readonly+sendto grant exactly those scopes for least-privilege setups. feat(permissions): non-cumulative union mode for --permissions (closes #808) by @justadityaraj in #811 - auth: The stdio server starts even when the OAuth callback port range is busy (e.g. a second Claude Desktop copy), and only needs a port once auth actually runs. fix(auth): don't exit the stdio server when the callback port range is busy by @cfdude in #1073
- auth: Notes that OAuth clients don't need the agentic setting. docs: note that OAuth clients do not need the agentic setting by @taylorwilsdon in #1275
- core: A streamed response that fails partway (e.g. a large download) is now aborted instead of ending as a clean, truncated 200. fix: stop MCPSessionMiddleware turning failed streamed responses into clean 200s by @123andy in #1262
Build & tests
- helm: The Helm chart is published to GHCR as an OCI artifact on
chart-v*tags and linted on PRs. ci(helm): publish chart to GHCR as OCI artifact by @DrFaust92 in #875 - tests:
UPDATE_GOLDENregenerates schema snapshots. test: add UPDATE_GOLDEN flag to regenerate schema snapshots by @WIZARD221 in #843
New Contributors
- @socromentoRep made their first contribution in #1253
- @axsaucedo made their first contribution in #1050
- @Omarinho12345 made their first contribution in #1246
- @johntrandall made their first contribution in #850
- @imparpaulo01 made their first contribution in #935
- @2000game made their first contribution in #1215
- @DannyGelf made their first contribution in #1279
Full Changelog: v2.1.1...v2.1.2