# io.github.mmedum/google-chat-mcp (mcpb · google-chat-mcp_6.1.0.mcpb)

Google Chat as MCP tools: read, search and write to your spaces, direct messages and sidebar.

- Trust score: 63/100 (medium)
- Change this week: +2
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-10-24

## Components

- mcpb · `google-chat-mcp_6.1.0.mcpb`: 63/100 (this document), [markdown](https://verifymcp.io/servers/mmedum-google-chat-mcp/https-github-com-mmedum-google-chat-mcp-releases-download-v2-3-1-google-chat-mcp.md), [page](https://verifymcp.io/servers/mmedum-google-chat-mcp/https-github-com-mmedum-google-chat-mcp-releases-download-v2-3-1-google-chat-mcp)

## Channel facts

- Registry: `mcpb`
- Package: `https://github.com/mmedum/google-chat-mcp/releases/download/v6.1.0/google-chat-mcp_6.1.0.mcpb`
- Version: `6.1.0`
- Transport: `stdio`
- SHA-256: `210f2c43afe76892409291a082e7036ce39d1165164c1bd3e02c48982046df2e`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-10-24.

- **Supply Chain Security**: 0/100
  - No malware scan is available for this kind of package: the supply-chain vendors we use do not cover it. This is a permanent gap in our coverage, not a finding about the package.
  - Known CVEs could not be checked: we found no dependency list to check in this bundle: either it runs a compiled binary, whose bundled manifests we do not read, or none of the package.json, requirements.txt, pyproject.toml or uv.lock files it ships for its runtime declares a dependency we can read (a requirements.txt that only points at a setup.py project, a local path, or a nested requirements file we cannot follow counts as none).
  - Install-script risk not yet assessed.
  - Dependency health could not be checked: we found no dependency list to check in this bundle: either it runs a compiled binary, whose bundled manifests we do not read, or none of the package.json, requirements.txt, pyproject.toml or uv.lock files it ships for its runtime declares a dependency we can read (a requirements.txt that only points at a setup.py project, a local path, or a nested requirements file we cannot follow counts as none).
- **Provenance & Transparency**: 100/100
  - Source repository is publicly reachable at the declared URL.
  - Cryptographically verified build provenance (signed, bound to mmedum/google-chat-mcp).
  - Clear OSI-approved license (Apache-2.0).
  - Actively maintained (last published 0 days ago).
  - Publishes a security disclosure policy (SECURITY.md).
- **Schema Quality & AI Usability**: 73/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 8071 tokens (~164/item across 49 items; 49 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 84/100
  - Stability check failed: the tool surface changed between 2.3.1 and 6.1.0: 5 tool removals, 0 breaking changes, 1 additions.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
  - Structured output schemas are declared (100% of tools); any adoption earns full credit.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - All 3 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.
  - An AI judge read all 50 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a current MCP spec version (2026-07-28).

**Unverified: 1 category.** A category scored 0 because we could not verify it: a data source with nothing on this package, evidence we could not reach, or a check we could not run. We only credit what we can confirm.

## Install

### How do I install the io.github.mmedum/google-chat-mcp server?

io.github.mmedum/google-chat-mcp ships as an MCPB bundle, a single file you download and open in an MCP host that supports MCPB bundles, such as Claude Desktop. The host reads the launch command from the bundle's own manifest, so there is no command to copy. Before opening it, check the file's SHA-256 matches the one the MCP registry declares for it, 210f2c43afe76892409291a082e7036ce39d1165164c1bd3e02c48982046df2e; the commands to do that are on this page. If it does not match, do not open it.

- Download bundle: `https://github.com/mmedum/google-chat-mcp/releases/download/v6.1.0/google-chat-mcp_6.1.0.mcpb`
- SHA-256: `210f2c43afe76892409291a082e7036ce39d1165164c1bd3e02c48982046df2e`

### Verify on macOS / Linux

```bash
echo "210f2c43afe76892409291a082e7036ce39d1165164c1bd3e02c48982046df2e  google-chat-mcp_6.1.0.mcpb" | shasum -a 256 -c
```

### Verify on Windows (PowerShell)

```powershell
(Get-FileHash -Algorithm SHA256 .\google-chat-mcp_6.1.0.mcpb).Hash -eq "210f2c43afe76892409291a082e7036ce39d1165164c1bd3e02c48982046df2e"
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-10-24 (score 63, +1)

- [functional] Package version: 6.0.0 → 6.1.0

### 2026-10-23 (score 62, −1)

- [security regression] Stability: 0.87 → fail
- [functional improvement] Schema quality: 9031 → 8071
- [functional] Package version: 5.1.1 → 6.0.0

### 2026-10-21 (score 63, +1)

No change was recorded against any check on this day. Stability & Change Management went from 80 to 83. That category is still filling its 30-day observation window: 24 days of observed history at the previous scan, 25 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-19 (score 62, +1)

No change was recorded against any check on this day. Stability & Change Management went from 73 to 77. That category is still filling its 30-day observation window: 22 days of observed history at the previous scan, 23 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-16 (score 61, +1)

No change was recorded against any check on this day. Stability & Change Management went from 63 to 67. That category is still filling its 30-day observation window: 19 days of observed history at the previous scan, 20 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-14 (score 60, +41)

- [security improvement] Injection markers: unverified → pass
- [functional improvement] Stability: unverified → 0.60
- [functional improvement] MCP protocol: unverified → pass
- [functional improvement] Tool coverage: unverified → 100
- [functional improvement] Maintenance: unverified → pass
- [functional] Package version: 4.0.0 → 5.1.1

### 2026-10-13 (score 19, +1)

- [functional improvement] Security disclosure: unverified → pass
- [functional] Package version: 4.0.0 → 5.1.1

### 2026-10-12 (score 18, +10)

- [security improvement] Provenance: unverified → pass
- [security] The attested source repository moved: mmedum/google-chat-mcp

## MCP tools (49)

### `add_member` (~254 tokens)

Invite someone in your organization into a space by email address, or add a Google Group. In a space that admits people from outside the organization, an address the organization's directory does not know is refused [blocked], and so is every Google Group, since a group brings in its outside members and anyone added to it later: add_external_member adds those. Someone already in the space is reported as an error rather than as a success, because the membership that exists belongs to whoever invited them first. Everyone joins as an ordinary member: Google ignores a role given here, silently. Set dry_run to see the request body without inviting anyone.

Input parameters:

- `dry_run` (boolean): return the request body without inviting anyone
- `group_name` (string): a Google Group to add, groups/{id}; find_group turns the group's email address into one. Google allows a group only in a named space, never a group chat or a direct message. Refused in a space that a…
- `space_id` (string, required): the space to invite them into, spaces/{id}
- `user_email` (string): their email address; search_people turns a name into one. Pass this or group_name, not both

Output parameters:

- `dry_run` (boolean): true when nobody was invited
- `group_name` (string): the group that was added, when it was a group
- `membership_name` (null|string): the new membership's resource name; remove_member takes it. Null after a dry run
- `rendered_payload` (null|object): on a dry run, the exact body that would have been sent; null on a real invite
- `role` (string): the role Google recorded, in its own spelling; empty when Google said nothing, which means an ordinary member
- `space_id` (string): the space they were invited into
- `user_email` (string): who was invited; empty when a group was added

### `add_reaction` (~83 tokens)

React to a message with a single unicode emoji. Reacting the same way twice is not an error: the reaction that is already there is returned instead.

Input parameters:

- `emoji` (string, required): a single unicode emoji, such as 👍; custom emoji are not supported here
- `message_name` (string, required): the message to react to, spaces/{space}/messages/{message}

Output parameters:

- `emoji` (string): the emoji character
- `reaction_name` (string): the reaction's resource name; remove_reaction takes it
- `user_id` (string): who reacted, users/{id}; the signed-in account

### `create_custom_emoji` (~179 tokens)

Add a custom emoji to your organization from an image on this machine. Everyone in the organization can then use it, so the name is worth agreeing first. The image must be a square PNG, JPEG or GIF, 64 to 500 pixels, under 256 KB.

Input parameters:

- `dry_run` (boolean): check the name and the image without creating anything
- `emoji_name` (string, required): the :shortcode: to type it by, colons included: lowercase letters, digits, hyphens and underscores, as in :party-parrot:
- `image_path` (string, required): a .png, .jpg or .gif on this machine. Google wants it square, between 64 and 500 pixels, and under 256 KB — the file is read and sent inside the request, so the size limit is checked here first

Output parameters:

- `bytes` (integer): the image's size, reported so a dry run tells you whether it fits
- `dry_run` (boolean): true when nothing was created
- `emoji_name` (string): the :shortcode: form, which is what you type in a message
- `name` (string): the resource name, customEmojis/{emoji}; get_custom_emoji and delete_custom_emoji take this
- `temporary_uri` (string): a link to the image that Google says is good for at least ten minutes. Not stored anywhere and not worth keeping

### `create_group_chat` (~110 tokens)

Start an unnamed group conversation with 2 to 20 people. Leave yourself out of member_emails: Google adds the signed-in account. A group chat cannot have a name; use create_space when you need one. Set dry_run to see the request body without creating anything.

Input parameters:

- `dry_run` (boolean): return the request body without creating anything
- `member_emails` (null|array, required): 2 to 20 email addresses, not counting you; Google adds the signed-in account itself

Output parameters:

- `dry_run` (boolean): true when nothing was created
- `member_count` (integer): how many people were asked for, not counting you
- `rendered_payload` (null|object): on a dry run, the exact body that would have been sent; null on a real create
- `space_id` (null|string): the new group chat's resource name; null after a dry run, because Google assigns it

### `create_section` (~108 tokens)

Add a custom section to your own Chat sidebar. Google does not merge sections by name, so two calls leave two sections with the same label: list_sections first if you mean to reuse one. Sections are per-user and change nobody else's view. Set dry_run to see the request body first. Needs the chat.users.sections scope.

Input parameters:

- `display_name` (string, required): what to call it, 1 to 80 characters
- `dry_run` (boolean): return the request body without creating anything

Output parameters:

- `display_name` (string): what it is called
- `dry_run` (boolean): true when nothing was changed
- `rendered_payload` (null|object): on a dry run, the exact body that would have been sent; null otherwise
- `section_name` (null|string): the section's resource name; null after a dry-run create, because Google assigns the id

### `create_space` (~206 tokens)

Create a named space, with up to 20 initial members or none at all. Leave yourself out of member_emails: Google adds the signed-in account. A space of your own is fine — invite people later with add_member. A space is created private; set_space_audience opens one to an audience. Set dry_run to see the request body without creating anything.

Input parameters:

- `audience` (string): private, or omit it: a space is created private. Opening one to a target audience is set_space_audience's, and anything else here is refused
- `display_name` (string, required): what to call the space, 1 to 128 characters
- `dry_run` (boolean): return the request body without creating anything
- `member_emails` (null|array): up to 20 email addresses, not counting you; Google adds the signed-in account itself. Omit it for a space of your own, which you can invite people to later with add_member

Output parameters:

- `audience` (null|string): always null: a space is created private, and set_space_audience opens one
- `display_name` (string): what it is called
- `dry_run` (boolean): true when nothing was created
- `member_count` (integer): how many people were asked for, not counting you
- `rendered_payload` (null|object): on a dry run, the exact body that would have been sent; null on a real create
- `space_id` (null|string): the new space's resource name; null after a dry run, because Google assigns it

### `download_attachment` (~129 tokens)

Save a message's attachment to the server's local directory. Name the message; if it carries more than one file, pass attachment_name from get_message. The result says where the file landed. A Google Drive attachment is refused with its file id: those bytes belong to Drive, not Chat. This needs the server to have been started with GCM_LOCAL_DIR.

Input parameters:

- `attachment_name` (string): which attachment, when the message carries more than one. get_message lists them as attachment_name
- `message_name` (string, required): the message the file is on, spaces/{space}/messages/{message}

Output parameters:

- `bytes` (integer): how many bytes were written
- `content_type` (string): the MIME type Google served it as
- `file_name` (string): the attachment's original name in Chat, which may differ from the name on disk
- `path` (string): where the file was written, inside the server's local directory
- `sha256` (string): the SHA-256 of the bytes written, hex encoded. Chat publishes no checksum of its own, so there is nothing here to verify against: this is for comparing the file with a copy elsewhere

### `find_direct_message` (~78 tokens)

Find the direct message with one person, and start one when there is none yet. Returns the space to pass to send_message. A newly started direct message is empty, so the other person sees nothing until a message is posted in it.

Input parameters:

- `user_email` (string, required): the other person's email address; search_people turns a name into one

Output parameters:

- `space_id` (string): the direct message's resource name; pass it to send_message

### `find_group` (~100 tokens)

Turn a Google Group's email address into its groups/{id} name, which add_member takes as group_name. Chat names a group only by that id. Looked up through Cloud Identity, which shows only the groups this account can see. Google answers an address no group has the same way as a group kept to its own members, so a refusal cannot say which.

Input parameters:

- `email` (string, required): the group's email address, such as team@example.com

Output parameters:

- `display_name` (null|string): the group's name, or null when Cloud Identity gave none
- `email` (string): the address that was looked up
- `group_name` (string): the group's resource name, groups/{id}; pass it to add_member as group_name

### `find_group_chats` (~134 tokens)

Find the group chats whose members are exactly you and the people you name. Use it before create_group_chat to reuse an existing chat rather than starting a second one with the same people. A chat with one extra member does not match. For a one-to-one conversation use find_direct_message.

Input parameters:

- `limit` (integer): how many to return, 1 to 30; default 10
- `member_emails` (null|array, required): the other people's email addresses, 1 to 49. You are always included, so pass only the others
- `page_token` (string): continue a previous call

Output parameters:

- `next_page_token` (string): pass back as page_token for the next page
- `result` (null|array): the group chats holding exactly you and the people named

### `get_availability` (~52 tokens)

Read your own Chat presence: active, idle, away or do not disturb, with any custom status. Yours only — Google's endpoint answers for the signed-in account and there is no way to ask about anyone else.

Output parameters:

- `do_not_disturb_until` (null|string): when do-not-disturb ends, RFC 3339 in UTC; null when you are not in it
- `state` (string): ACTIVE, IDLE, AWAY, DO_NOT_DISTURB, or STATE_UNSPECIFIED for a state this server does not recognize. IDLE is Google's to report, not yours to set
- `status_emoji` (string): the emoji beside that status
- `status_expires` (null|string): when the custom status lapses, RFC 3339 in UTC; null when it does not
- `status_text` (string): the custom status beside your name, if you have one

### `get_custom_emoji` (~50 tokens)

Read one custom emoji by its resource name, which list_custom_emojis reports.

Input parameters:

- `name` (string, required): the emoji's resource name, customEmojis/{emoji}, from list_custom_emojis

Output parameters:

- `emoji_name` (string): the :shortcode: form, which is what you type in a message
- `name` (string): the resource name, customEmojis/{emoji}; get_custom_emoji and delete_custom_emoji take this
- `temporary_uri` (string): a link to the image that Google says is good for at least ten minutes. Not stored anywhere and not worth keeping

### `get_member` (~101 tokens)

Read one membership: who or what it is, their role, and whether they have joined. list_members answers who is in a space; this answers what a membership is, which is what to check before changing a role or removing someone — a membership can name a Google Group, and removing that one removes everyone in the group from the space.

Input parameters:

- `membership_name` (string, required): the membership to read, spaces/{space}/members/{member}, from list_members

Output parameters:

- `affiliation` (string): INTERNAL for someone in your organization, EXTERNAL for a guest, MANAGED_EXTERNAL for a guest their own organization manages. Empty when Google said nothing. A space with external members is one to t…
- `display_name` (null|string): what to call them, or null when Google gave no name
- `email` (null|string): the person's or the group's email address; null when neither Chat, the People API nor Cloud Identity named one
- `group_members` (null|array): for a GROUP row of list_members with expand_groups: who is in the group, directly, up to 200. Null otherwise, and when they could not be read
- `group_members_missing` (null|string): why group_members could not be read, such as a group that does not show its members to you; null when they were read or not asked for
- `group_members_more` (boolean): true when the group has more direct members than group_members holds
- `kind` (string): HUMAN for a person, GROUP for a Google Group whose members are in the space through it
- `member_id` (string): who the membership is for: users/{id} for a person, groups/{id} for a group
- `membership_name` (string): the membership's own resource name, spaces/{space}/members/{member}. get_member, update_member_role and remove_member take THIS, not member_id
- `role` (string): ROLE_MEMBER, ROLE_MANAGER, ROLE_ASSISTANT_MANAGER, or ROLE_UNSPECIFIED for a role this server does not recognize
- `state` (string): JOINED for someone who is in the space, INVITED for someone who has been asked and has not accepted, NOT_A_MEMBER, or MEMBERSHIP_STATE_UNSPECIFIED

### `get_message` (~154 tokens)

Fetch a single message by its resource name (spaces/{space}/messages/{message}). Reaction summaries are inline; reactions_paged true means there were too many to inline and list_reactions has the detail. Attachments are listed with the name download_attachment takes. links is what the text links to — a message whose body is a link names the target there and nowhere else — and formatted_text is the same body with Chat's markup left in. quote is the message this one replies to or forwards, as it read when it was quoted; a forward carries the whole snapshot, because the space it came from is often one you cannot read.

Input parameters:

- `message_name` (string, required): the message, spaces/{space}/messages/{message}

Output parameters:

- `attachments` (null|array): the files on the message, with the name download_attachment takes; empty when it carries none. A message that is only a file has empty text and its file here
- `formatted_text` (null|string): the same body with Chat's markup left in — bold, italics, mentions and the URL behind a link — or null when the markup says nothing the plain text does not
- `last_update_time` (null|string): when it was last edited, or null when it never was
- `links` (null|array): what the text links to; empty when it links to nothing
- `message_id` (string): the message's resource name
- `quote` (null|object): the message this one quotes or forwards; null when it quotes nothing
- `reactions` (null|array): one entry per distinct emoji on the message
- `reactions_paged` (boolean): true when the summaries were left out because there were too many; call list_reactions for the detail
- `sender_display_name` (null|string): the sender's name, or null when Google gave none
- `sender_email` (null|string): the sender's email address, or null when it could not be resolved
- `sender_user_id` (string): who sent it, users/{id}
- `space_id` (string): the space it was posted in
- `text` (string): the message body as plain text
- `thread_id` (string): the thread it belongs to
- `thread_reply` (boolean): true when it was posted as a reply in its thread, false when it started the thread
- `timestamp` (string): when the message was created, RFC 3339 in UTC

### `get_messages` (~315 tokens)

Read recent messages from a space. Returns up to limit messages (default 20, max 100), newest first; page with page_token and next_page_token. Keep paging while next_page_token is non-null: an EMPTY result with a token still on it does not mean the space is empty, because Google applies the page size before it filters. Sender email is the one Chat sends, or a People API lookup when Chat sends none, and is null when both come back empty. Each message carries links: what its text links to, which Chat keeps out of the body, so a message reading as a bare word may be a link to something. quote is what a message replies to or forwards, which Chat also keeps out of the body. Each message also carries its files, reaction counts, when it was edited and whether it replies in its thread; a message that is only a file has empty text.

Input parameters:

- `before` (string): only messages created before this time; RFC 3339. With since, a window, such as what was said on one day
- `limit` (integer): how many to return, 1 to 100; default 20
- `page_token` (string): next_page_token from a previous call
- `since` (string): only messages created after this time; RFC 3339, such as 2026-01-01T00:00:00Z
- `space_id` (string, required): the space to read, spaces/{id}, from list_spaces

Output parameters:

- `next_page_token` (null|string): pass this back as page_token to read the next page; null when this is the last one
- `result` (null|array): the messages that were read
- `unparsed` (integer): messages that were read but could not be understood, and so are missing from result. Non-zero means this listing is INCOMPLETE, which is not the same as the space being quiet

### `get_space` (~60 tokens)

Fetch one Google Chat space by its resource name. Use it to identify an unnamed direct message or group chat, or to confirm a space's metadata before writing to it.

Input parameters:

- `space_id` (string, required): the space, spaces/{id}, from list_spaces

Output parameters:

- `access_state` (null|string): PRIVATE when only people added or invited can find the space, DISCOVERABLE when a target audience can; null when Google did not say, as for a direct message
- `audience` (null|string): the target audience that can find the space, join it and read it, audiences/{id}; null for a private space, and for one an audience can find but not join
- `create_time` (null|string): when the space was created, RFC 3339 in UTC; null when Google did not say
- `description` (null|string): what the space is for, as its managers wrote it; null when it has none
- `display_name` (string): what to call the space; a direct message or group chat has no name of its own, so a label is supplied
- `external_user_allowed` (null|boolean): true when people outside the organization may join; null when Google did not say
- `group_member_count` (null|integer): Google Groups that have joined; null when Google did not say
- `guidelines` (null|string): the rules its managers set for it; null when it has none
- `history_state` (null|string): HISTORY_OFF when messages are kept for 24 hours, HISTORY_ON when the organization's retention rules decide; null when Google did not say
- `human_member_count` (null|integer): people who have joined, not counting those who are in only through a group; null when Google did not say
- `last_active_time` (null|string): when the last message was posted, RFC 3339 in UTC; null when Google did not say
- `members_can_post` (null|boolean): false when only managers may post, as in an announcement space; null when Google did not say
- `single_user_bot_dm` (null|boolean): true when the space is a direct message with a Chat app rather than a person; null when Google did not say
- `space_id` (string): the space's resource name, spaces/{id}
- `space_uri` (null|string): the link that opens the space in Chat; null when Google did not say
- `type` (string): SPACE, DIRECT_MESSAGE, GROUP_CHAT, or SPACE_TYPE_UNSPECIFIED for a kind this server does not recognize

### `get_space_event` (~86 tokens)

One event from a space by its resource name, which list_space_events reports. The payload is the resource as it is now, not as it was: an event about a message that has since been edited names the message, and get_message returns the current text.

Input parameters:

- `event_name` (string, required): the event, spaces/{space}/spaceEvents/{event}, from list_space_events

Output parameters:

- `batch` (boolean): true when Google collapsed several changes of one type into this event. It does that on its own, so a batch arrives even though only the plain type was asked for
- `event_name` (string): the event's resource name; pass it to get_space_event
- `event_time` (string): when it happened, RFC 3339 in UTC
- `event_type` (string): Google's own event type, such as google.workspace.chat.message.v1.created
- `kind` (string): what changed: message, membership, reaction or space
- `resources` (null|array): the resource names the event covers, one per change. Read a message with get_message; a deleted one is a tombstone and only its name survives

### `get_space_notification_setting` (~54 tokens)

Read what Chat tells you about a space: which messages notify you, and whether the space is muted. Your own setting, not the space's.

Input parameters:

- `space_id` (string, required): the space, spaces/{id}

Output parameters:

- `mute_setting` (string): MUTED silences the space whatever notification_setting says; UNMUTED respects it
- `name` (string): the setting's own resource name
- `notification_setting` (string): ALL for every new thread and mention, MAIN_CONVERSATIONS for the main conversation only, FOR_YOU for mentions and followed threads, OFF for none, or NOTIFICATION_SETTING_UNSPECIFIED for a value this…

### `get_space_read_state` (~65 tokens)

Read how far you have read in a space. This is your own state, not the space's: two people reading the same space get different answers. Only top-level messages count, not thread replies.

Input parameters:

- `space_id` (string, required): the space, spaces/{id}

Output parameters:

- `last_read_time` (null|string): when you last read here, RFC 3339 in UTC; null when Google has recorded none, which is what a space you have never opened looks like
- `name` (string): the read state's own resource name

### `get_thread` (~188 tokens)

Read one thread's messages, oldest first. Give the parent space_id and the thread_name (spaces/{space}/threads/{thread}), which every message carries as thread_id. Default limit 50, max 100; page with page_token and next_page_token. A non-null next_page_token means the thread is longer than what came back, so do not read the result as the whole thread. Each message carries its links, what it quotes, its files and reaction counts, and when it was edited.

Input parameters:

- `limit` (integer): how many to return, 1 to 100; default 50
- `page_token` (string): next_page_token from a previous call
- `space_id` (string, required): the thread's parent space, spaces/{id}
- `thread_name` (string, required): the thread, spaces/{space}/threads/{thread}, from a message's thread_id

Output parameters:

- `next_page_token` (null|string): pass this back as page_token to read the next page; null when this is the last one
- `result` (null|array): the messages that were read
- `unparsed` (integer): messages that were read but could not be understood, and so are missing from result. Non-zero means this listing is INCOMPLETE, which is not the same as the space being quiet

### `get_thread_read_state` (~70 tokens)

Read how far you have read in one thread. Your own state, as with a space.

Input parameters:

- `space_id` (string, required): the thread's space, spaces/{id}
- `thread_name` (string, required): the thread, spaces/{space}/threads/{thread}, from a message's thread_id

Output parameters:

- `last_read_time` (null|string): when you last read here, RFC 3339 in UTC; null when Google has recorded none, which is what a space you have never opened looks like
- `name` (string): the read state's own resource name

### `list_custom_emojis` (~90 tokens)

List your organization's own emoji, the ones people type as :shortcodes:. Custom emoji exist only on Google Workspace accounts and only when an administrator has turned them on.

Input parameters:

- `limit` (integer): how many to return, 1 to 200; default 50
- `mine_only` (boolean): only the emoji this account created
- `page_token` (string): continue a previous call

Output parameters:

- `next_page_token` (string): pass back as page_token for the next page
- `result` (null|array): the organization's custom emoji

### `list_members` (~266 tokens)

List the members of a Google Chat space: people, Google Groups, and anyone invited who has not joined yet. Every row carries kind (HUMAN or GROUP) and state (JOINED, INVITED, NOT_A_MEMBER), so check state before reporting someone as present. People come back with the email Chat sends, or one looked up through the People API when Chat sends none; a Google Group comes back with the address and name Cloud Identity gives it, or with only groups/{id} when that lookup is not granted. Default 50 entries; pass limit (1-200) to widen, and page with page_token and next_page_token. A non-null next_page_token means the space has more members than came back, so do not report the result as the whole membership.

Input parameters:

- `expand_groups` (boolean): also list who is in each Google Group member, one level down: up to 200 people for each of the first 10 groups. Google shows a group's members only to someone the group lets see them
- `limit` (integer): how many to return, 1 to 200; default 50
- `page_token` (string): next_page_token from a previous call
- `space_id` (string, required): the space, spaces/{id}

Output parameters:

- `next_page_token` (null|string): pass this back as page_token to read the next page; null when this is the last one
- `result` (null|array): who is in the space
- `unparsed` (integer): memberships that were read but could not be understood, and so are missing from result. Non-zero means this listing is INCOMPLETE: a short list otherwise reads as a small space

### `list_pinned_messages` (~92 tokens)

List the messages pinned in a space. A pin is how a space marks something worth keeping to hand, so this is a good first read for what a space is about.

Input parameters:

- `limit` (integer): how many to return, 1 to 100; default 50
- `page_token` (string): continue a previous call
- `space_id` (string, required): the space, spaces/{id}

Output parameters:

- `next_page_token` (string): pass back as page_token for the next page
- `result` (null|array): the pinned messages, which are the ones the space treats as important

### `list_reactions` (~107 tokens)

List the reactions on a single message: who reacted and with what. Default limit 50, max 200; page with page_token and next_page_token. Custom emoji are left out, having no character to show.

Input parameters:

- `limit` (integer): how many to return, 1 to 200; default 50
- `message_name` (string, required): the message, spaces/{space}/messages/{message}
- `page_token` (string): next_page_token from a previous call

Output parameters:

- `next_page_token` (null|string): pass this back as page_token to read the next page; null when this is the last one
- `reactions` (null|array): one entry per person per emoji

### `list_section_items` (~159 tokens)

List the spaces filed under a section. Pass section_name to read one section, space_id to find which section a single space sits in, or both to check one against the other; at least one is required. A non-null next_page_token means limit cut the listing short, so page rather than treat it as the whole section. Needs the chat.users.sections.readonly scope.

Input parameters:

- `limit` (integer): how many to return, 1 to 100; default 50
- `page_token` (string): next_page_token from a previous call
- `section_name` (string): read one section, users/{user}/sections/{section}
- `space_id` (string): find which section this space sits in, spaces/{id}

Output parameters:

- `items` (null|array): the spaces filed under the section
- `next_page_token` (null|string): non-null means limit cut the listing short. A bulk re-sort built on a truncated listing skips the spaces it never saw, so page rather than assume
- `unparsed` (integer): rows this listing could not read and skipped. Non-zero means the result is INCOMPLETE, not that the section is that small

### `list_sections` (~109 tokens)

List the sections in the caller's own Chat sidebar: the system ones ('(direct messages)', '(spaces)', '(apps)') plus any custom ones they made. Sections are per-user and change nobody else's view. A non-null next_page_token means more sections exist beyond limit. Needs the chat.users.sections.readonly scope.

Input parameters:

- `limit` (integer): how many to return, 1 to 100; default 50
- `page_token` (string): next_page_token from a previous call

Output parameters:

- `next_page_token` (null|string): non-null means limit cut the listing short and more sections exist; pass it back as page_token
- `sections` (null|array): the caller's own sidebar sections
- `unparsed` (integer): rows this listing could not read and skipped. Non-zero means the result is INCOMPLETE and this server's models are stale, not that the sidebar is that small

### `list_space_events` (~270 tokens)

What changed in a space over the last 28 days: messages posted, edited or deleted, people joining or leaving, reactions, and edits to the space itself. Name at least one event type. Events come oldest first and each names the resources it covers, which you read with get_message, get_member or get_space. Google keeps 28 days and no more, and it answers a busy space with batch events covering several changes at once.

Input parameters:

- `event_types` (null|array, required): what to list, at least one: message_created, message_updated, message_deleted, membership_created, membership_updated, membership_deleted, reaction_created, reaction_deleted, space_updated. Google re…
- `limit` (integer): how many events to return, 1 to 100; default 50
- `page_token` (string): continue from a previous next_page_token
- `since` (string): only events after this time, exclusive; RFC 3339. Google keeps 28 days and nothing older can be asked for
- `space_id` (string, required): the space to read, spaces/{id}
- `until` (string): only events up to this time, inclusive; RFC 3339. Defaults to now

Output parameters:

- `events` (null|array): what changed, oldest first
- `next_page_token` (string): pass back as page_token for the next page
- `unparsed` (integer): events Google sent that carried nothing this server could name. Non-zero means this page is INCOMPLETE, which is not the same as nothing having happened

### `list_spaces` (~161 tokens)

List Google Chat spaces (direct messages, group chats, named spaces) the authenticated user belongs to. Defaults to 50 entries; pass limit (1-200) to widen and space_type ('SPACE' | 'DIRECT_MESSAGE' | 'GROUP_CHAT') to narrow, and page with page_token and next_page_token. A non-null next_page_token means the account is in more spaces than came back. Use this to find a space's resource name before reading its messages.

Input parameters:

- `limit` (integer): how many to return, 1 to 200; default 50
- `page_token` (string): next_page_token from a previous call
- `space_type` (string): narrow to SPACE, DIRECT_MESSAGE or GROUP_CHAT; omit for every kind

Output parameters:

- `next_page_token` (null|string): pass this back as page_token to read the next page; null when this is the last one
- `result` (null|array): the spaces the account belongs to

### `mark_space_read` (~77 tokens)

Mark a space as read up to now, clearing its unread badge for you and nobody else. Google pulls the mark back to the newest message's own time, so the answer reports what it recorded.

Input parameters:

- `dry_run` (boolean): check the arguments without changing anything
- `space_id` (string, required): the space, spaces/{id}

Output parameters:

- `dry_run` (boolean): true when nothing was changed
- `last_read_time` (string): the mark Google recorded, which is not always what was asked for: marking read is pulled back to the newest message's own time
- `name` (string): the read state's resource name; empty after a dry run
- `unread` (boolean): true when this call rewound the mark rather than clearing it

### `mark_space_unread` (~135 tokens)

Rewind your read mark in a space, so every top-level message after from_time is unread again. Pass the timestamp of the message you want to come back to; get_messages reports it. Affects you and nobody else.

Input parameters:

- `dry_run` (boolean): check the arguments without changing anything
- `from_time` (string, required): rewind your read mark to this time, RFC 3339: every top-level message after it becomes unread. get_messages reports each message's timestamp, so pass the timestamp of the message you want to come bac…
- `space_id` (string, required): the space, spaces/{id}

Output parameters:

- `dry_run` (boolean): true when nothing was changed
- `last_read_time` (string): the mark Google recorded, which is not always what was asked for: marking read is pulled back to the newest message's own time
- `name` (string): the read state's resource name; empty after a dry run
- `unread` (boolean): true when this call rewound the mark rather than clearing it

### `move_space_to_section` (~227 tokens)

File a space under a section in your own sidebar. Every space already sits in some section, a default one until you move it, so this both files and re-files, and reports moved false when the space is already where you want it. For a bulk sort, read each section once with list_section_items and pass the item_name it gives you: that skips the per-space lookup. Set dry_run to see which section the space would leave without writing. Needs the chat.users.sections scope.

Input parameters:

- `dry_run` (boolean): look up where the space sits without moving it
- `item_name` (string): the space's current sidebar entry, from list_section_items. Passing it skips a lookup, which is what makes a bulk sort cost one listing per section instead of a request per space. Nothing re-checks t…
- `section_name` (string, required): where to file it, users/{user}/sections/{section}
- `space_id` (string, required): the space to file, spaces/{id}

Output parameters:

- `dry_run` (boolean): true when nothing was moved
- `from_section` (string): where the space sat before, a default section when it had never been filed. Resolved before anything is written, so a dry run reports it too
- `item_name` (string): the sidebar entry after the move; feed it back in for a bulk sort. A move renames it, so the one you passed in no longer exists
- `moved` (boolean): false without an error in two cases: a dry run, and a space already in the target section
- `rendered_payload` (null|object): on a dry run that would move something, the exact body; null on a real move and on a space already in place
- `section_name` (string): the section it was asked to go to
- `space_id` (string): the space that was filed

### `pin_message` (~82 tokens)

Pin a message in its space, so everyone in the space sees it in the pinned list. The space is taken from the message name. Pinning is visible to everyone.

Input parameters:

- `dry_run` (boolean): check the arguments without changing anything
- `message_name` (string, required): the message, spaces/{space}/messages/{message}. The space is taken from it

Output parameters:

- `dry_run` (boolean): true when nothing was changed
- `message_id` (string): the message that was named
- `pin_name` (string): the pin's resource name; empty after a dry run
- `pinned` (boolean): true only when this call pinned the message
- `unpinned` (boolean): true only when this call removed a pin. False can mean the message was not pinned

### `position_section` (~183 tokens)

Move a section within your sidebar. Pass exactly one of sort_order (absolute, 1 and up) or relative_position (START or END). Prefer relative_position when arranging several: Google documents sort_order as inserting at that rank and shifting the rest down, but a run of absolute inserts does not settle where that implies, so build an order by moving each to START in reverse. Set dry_run to see the request body first. Needs the chat.users.sections scope.

Input parameters:

- `dry_run` (boolean): return the request body without moving anything
- `relative_position` (string): START or END; pass this or sort_order, not both
- `section_name` (string, required): the section to move, users/{user}/sections/{section}
- `sort_order` (null|integer): an absolute rank, 1 and up; pass this or relative_position, not both

Output parameters:

- `dry_run` (boolean): true when nothing was moved
- `rendered_payload` (null|object): on a dry run, the exact body that would have been sent; null on a real move
- `section_name` (string): the section that was moved
- `sort_order` (null|integer): the rank Google reports after the move, when it reports one; null after a dry run

### `remove_reaction` (~171 tokens)

Delete a reaction. Pass reaction_name on its own, or message_name with emoji and user_email to look it up first. The lookup matches on the reactor's email address, so it fails rather than reporting nothing to delete when someone who reacted cannot be resolved: a silent no was the one answer it must not give. Removed false means there was no such reaction.

Input parameters:

- `emoji` (string): the emoji to remove; pass it with message_name and user_email
- `message_name` (string): the message the reaction is on; pass it with emoji and user_email
- `reaction_name` (string): the reaction to delete, from list_reactions or add_reaction. Pass this on its own
- `user_email` (string): whose reaction to remove; pass it with message_name and emoji

Output parameters:

- `reaction_name` (null|string): the reaction that was deleted; null when the lookup found none
- `removed` (boolean): false when there was no such reaction to delete, which is not an error

### `rename_section` (~105 tokens)

Change a custom section's label. Only custom sections can be renamed; Google refuses a patch against a system one. Set dry_run to see the patch body first. Needs the chat.users.sections scope.

Input parameters:

- `display_name` (string, required): the new label, 1 to 80 characters
- `dry_run` (boolean): return the patch body without applying it
- `section_name` (string, required): the section to rename, users/{user}/sections/{section}, from list_sections

Output parameters:

- `display_name` (string): what it is called
- `dry_run` (boolean): true when nothing was changed
- `rendered_payload` (null|object): on a dry run, the exact body that would have been sent; null otherwise
- `section_name` (null|string): the section's resource name; null after a dry-run create, because Google assigns the id

### `search_messages` (~641 tokens)

Search Google Chat message history. Two searches in one tool. Pass query and Google searches every space you can see, matching whole words; narrow it with space_id, sender_email, mentions_me, has_attachment, has_link, unread_only and a time window. Pass regex instead and this server scans one space itself, which is the only way to match a pattern or part of a word — it needs space_id, reads pages of history, and takes none of the filters. Prefer query. If cap_reached is true the answer is partial; if unparsed is non-zero it is incomplete, and saying the space is empty would be wrong. Each hit carries its links, what it quotes, its files and reaction counts, and when it was edited.

Input parameters:

- `by_relevance` (boolean): order by relevance instead of newest first. Google has this in Developer Preview and refuses it outside that program
- `created_after` (string): only messages created at or after this time; RFC 3339, such as 2026-01-01T00:00:00Z. Strongly recommended for a regex scan: an unbounded scan of a busy space stops at the page cap and returns a parti…
- `created_before` (string): only messages created before this time; RFC 3339
- `has_attachment` (boolean): only messages carrying an attachment. Google's search only
- `has_link` (boolean): only messages containing a hyperlink. Google's search only
- `limit` (integer): how many matches to return, 1 to 100; default 50
- `max_pages` (integer): how many pages of history a regex scan may read, 1 to 50; default 10
- `mentions_me` (boolean): only messages that @-mention you. Google's search only
- `page_token` (string): continue Google's search from a previous next_page_token
- `query` (string): keywords for Google's own search, matched as a phrase across whole words. Quotes, backslashes and brackets are not allowed; use regex for a literal or partial-word match
- `regex` (string): a regular expression in RE2 syntax, scanned by this server over one space rather than by Google. The only way to match a pattern or part of a word, and the slowest: it reads pages of history. Cannot…
- `sender_email` (string): only messages from this person. Google's search only
- `space_id` (string): the space to search, spaces/{id}. Google's search takes every space you can see when this is omitted; a regex scan needs it
- `space_name` (string): only messages in spaces whose display name holds every one of these words, such as Project Alpha. Google searches its top five matching spaces. Google's search only
- `space_type` (string): only messages in spaces of this kind: SPACE, GROUP_CHAT or DIRECT_MESSAGE. Google's search only
- `unread_only` (boolean): only messages you have not read. Google's search only, and it needs the read-state scope as well as the message one

Output parameters:

- `cap_reached` (boolean): true when there is more than was returned: a scan that hit max_pages or filled the limit, or a Google search with a further page. The answer is partial, so say so
- `matches` (null|array): the messages that matched, newest first
- `next_page_token` (string): pass back as page_token to continue Google's search; a regex scan has none
- `scanned` (integer): how many messages were read before filtering. Google filters upstream, so its search reports what it returned
- `server_side` (boolean): true when Google ran the search, false when this server scanned one space for a pattern
- `unparsed` (integer): messages that were read but could not be searched. Non-zero means this result is INCOMPLETE, which is not the same as no matches; say so rather than reporting the space as empty

### `search_people` (~160 tokens)

Look someone up across the caller's Workspace directory and their own contacts, and get their email address. Each hit says which source produced it. Directory hits are remembered, so a later get_messages or list_members resolves the same person without another lookup. Use it to turn a name or a fragment of one into the email address the other tools take.

Input parameters:

- `limit` (integer): how many to return, 1 to 100; default 10
- `query` (string, required): a name or email fragment, 1 to 200 characters
- `sources` (null|array): which upstreams to ask: DIRECTORY for the Workspace directory, CONTACTS for the caller's own contacts. Default asks both, which covers a Workspace account and a personal one

Output parameters:

- `people` (null|array): the matches, deduplicated across sources
- `sources_attempted` (null|array): which upstreams were asked
- `sources_succeeded` (null|array): which upstreams answered. A source that was attempted but did not succeed refused, and the matches come from the rest
- `total_returned` (integer): how many matches are in people

### `search_spaces` (~240 tokens)

Search the named Google Chat spaces you are a member of by display name, or every space in the Workspace with use_admin_access. Use find_group_chats for a group chat, which this cannot return. Matching is by word prefix. Without admin access Google returns a single page of up to 100 and no total.

Input parameters:

- `display_name` (string): match spaces whose name begins with these words; matching is by word prefix, not substring, so 'eng' finds 'Engineering' but 'ing' does not. Omit to list every named space the other filters allow
- `external_user_allowed` (null|boolean): true for spaces that admit people outside the organization, false for those that do not; omit for both
- `limit` (integer): how many to return, 1 to 100; default 50
- `page_token` (string): continue a previous search; Google returns a token only with admin access
- `use_admin_access` (boolean): search every space in the Workspace rather than the ones you can see. Needs Workspace admin rights and the admin toolset, which is off unless GCM_TOOLSETS names it

Output parameters:

- `next_page_token` (string): pass back as page_token for the next page; only ever set under admin access
- `result` (null|array): the named spaces that matched
- `total_size` (integer): how many spaces matched in total, an estimate above 10000; only ever set under admin access

### `send_message` (~591 tokens)

Post a text message to a Chat space, a group chat or a direct message. The body is posted exactly as given: nothing is added to it, and nothing in it is rewritten. To @mention someone, put <users/their@address> in the text yourself; a mention of everyone in the space, <users/all>, is refused [blocked], since it notifies every member. Pass thread_name to reply in an existing thread, which every message carries as thread_id. Set dry_run to see the request body without posting. The post carries a client-assigned id, so this server's own retries cannot leave two copies — but calling the tool again after an error can, because that is a new post. Read the space first if you are unsure. To send a file, upload it with upload_attachment first and pass the token it returns.

Input parameters:

- `attachment_upload_token` (string): attach a file uploaded beforehand: the upload_token from upload_attachment, for the same space. One file per message, and the token is spent once it is posted
- `client_message_id` (string): an id you choose, so that repeating this exact call lands on the same message instead of posting a second one. Must start with 'client-', be at most 63 characters, and hold only lowercase letters, di…
- `dry_run` (boolean): return the request body without posting; call again without it to post
- `markdown` (boolean): read the text as standard Markdown rather than Chat's own syntax: **bold**, [label](https://example.com), lists and code blocks. A mention is then written <chat-user data-email="their@address">; a me…
- `quote_message` (string): quote this message above the text, as a reply to it: spaces/{space}/messages/{message}, in the same space. Google refuses to forward a message under a person's sign-in, so one from another space cann…
- `reply_fallback` (boolean): if the thread named is gone, start a new thread instead of failing. Only meaningful with thread_name; the default fails, so a reply never lands somewhere unexpected
- `space_id` (string, required): the space to post in, spaces/{id}, from list_spaces or find_direct_message
- `text` (string, required): the message body, 1 to 4096 characters; posted exactly as given. To @mention someone, write <users/their@address> in the text: Google resolves the address itself when the server is signed in as a per…
- `thread_name` (string): reply in this thread, spaces/{space}/threads/{thread}; omit to start a new one

Output parameters:

- `dry_run` (boolean): true when nothing was posted
- `message_id` (null|string): the new message's resource name; null after a dry run, because nothing was posted
- `rendered_payload` (null|object): on a dry run, the exact body that would have been posted; null on a real post
- `space_id` (string): the space it went to
- `thread_id` (null|string): the thread it landed in; null after a dry run

### `set_availability` (~171 tokens)

Set your own Chat presence to ACTIVE, AWAY or DO_NOT_DISTURB. Do not disturb needs an expiry — minutes or until — which Google requires and caps at a year. Other people see this, so it is worth asking before silencing someone's notifications on their behalf.

Input parameters:

- `dry_run` (boolean): check the arguments without changing anything
- `minutes` (integer): how long do-not-disturb should last. Pass this or until, and only with DO_NOT_DISTURB, which Google requires an expiry for and caps at a year
- `state` (string, required): ACTIVE, AWAY or DO_NOT_DISTURB. IDLE cannot be set: Google decides it
- `until` (string): when do-not-disturb should end, RFC 3339. Pass this or minutes

Output parameters:

- `do_not_disturb_until` (null|string): when do-not-disturb ends, RFC 3339 in UTC; null when you are not in it
- `dry_run` (boolean): true when nothing was changed
- `state` (string): ACTIVE, IDLE, AWAY, DO_NOT_DISTURB, or STATE_UNSPECIFIED for a state this server does not recognize. IDLE is Google's to report, not yours to set
- `status_emoji` (string): the emoji beside that status
- `status_expires` (null|string): when the custom status lapses, RFC 3339 in UTC; null when it does not
- `status_text` (string): the custom status beside your name, if you have one

### `set_custom_status` (~214 tokens)

Set the text and emoji beside your name in Chat, or clear it. Google wants both together and refuses one without the other; a custom emoji is not accepted here, only a Unicode one. An expiry is optional, unlike do-not-disturb's. Everyone who sees you in Chat sees this.

Input parameters:

- `clear` (boolean): remove the status you have instead of setting one. Takes no other argument
- `dry_run` (boolean): return the request body without changing anything
- `emoji` (string): one Unicode emoji beside the text. Google requires it alongside the text and refuses one of your organization's custom emoji here. Required unless clear is set
- `minutes` (integer): how long the status should last. Pass this or until; leave both out and it stays until you change it
- `text` (string): what the status says, up to 64 characters. Required unless clear is set
- `until` (string): when the status should lapse, RFC 3339. Pass this or minutes

Output parameters:

- `cleared` (boolean): true when the status was removed rather than set
- `do_not_disturb_until` (null|string): when do-not-disturb ends, RFC 3339 in UTC; null when you are not in it
- `dry_run` (boolean): true when nothing was changed
- `rendered_payload` (null|object): on a dry run, the exact body that would have been sent; null otherwise
- `state` (string): ACTIVE, IDLE, AWAY, DO_NOT_DISTURB, or STATE_UNSPECIFIED for a state this server does not recognize. IDLE is Google's to report, not yours to set
- `status_emoji` (string): the emoji beside that status
- `status_expires` (null|string): when the custom status lapses, RFC 3339 in UTC; null when it does not
- `status_text` (string): the custom status beside your name, if you have one

### `unpin_message` (~87 tokens)

Remove a message's pin. Takes the message, not the pin: Google gives a pin the message's own id. A message that was not pinned reports unpinned false rather than failing.

Input parameters:

- `dry_run` (boolean): check the arguments without changing anything
- `message_name` (string, required): the message, spaces/{space}/messages/{message}. The space is taken from it

Output parameters:

- `dry_run` (boolean): true when nothing was changed
- `message_id` (string): the message that was named
- `pin_name` (string): the pin's resource name; empty after a dry run
- `pinned` (boolean): true only when this call pinned the message
- `unpinned` (boolean): true only when this call removed a pin. False can mean the message was not pinned

### `update_member_role` (~153 tokens)

Make a manager or an assistant manager an ordinary member of a space again: role MEMBER. Demoting the last manager may leave nobody able to administer the space. Making someone a manager is refused [blocked] here; promote_member does it. Role is the only thing this changes. Set dry_run to see the request body without sending it.

Input parameters:

- `dry_run` (boolean): return the request body without changing anything
- `membership_name` (string, required): the membership to change, spaces/{space}/members/{member}, from list_members
- `role` (string, required): MEMBER, to make a manager an ordinary member again. MANAGER and ASSISTANT_MANAGER are refused here: making someone a manager is promote_member's

Output parameters:

- `dry_run` (boolean): true when nothing was changed
- `membership_name` (string): the membership that was named
- `rendered_payload` (null|object): on a dry run, the exact body that would have been sent; null on a real change
- `role` (string): the role Google recorded, in its own spelling; after a dry run, the role that was asked for

### `update_message` (~144 tokens)

Replace the text of a message you sent. Text only: cards and attachments are left untouched, and editing them needs an identity this server does not have. An edit that newly mentions everyone in the space, <users/all>, is refused [blocked], since it notifies every member. Set dry_run to see the patch body without applying it. Needs the restricted-tier chat.messages scope.

Input parameters:

- `dry_run` (boolean): return the patch body without applying it
- `message_name` (string, required): the message to edit, spaces/{space}/messages/{message}; you must be its sender
- `text` (string, required): the replacement body, 1 to 4096 characters

Output parameters:

- `dry_run` (boolean): true when nothing was changed
- `message_name` (string): the message that was edited
- `rendered_payload` (null|object): on a dry run, the exact patch body; null on a real edit
- `text` (string): the body it now has

### `update_space` (~253 tokens)

Rename a space, change its description, or make it private again. Pass at least one; an empty edit is refused. Editing the description keeps the space's guidelines: Google's mask covers both at once, so the server reads them and sends them back unchanged. audience private makes a space private; Google takes it only on its own, from a space manager. Opening a space to an audience is set_space_audience's. Set dry_run to see the patch body first. Needs the restricted-tier chat.spaces scope.

Input parameters:

- `audience` (string): private to make the space private again; omit it to leave access alone. Opening a space to a target audience is set_space_audience's, and anything else here is refused. Change it in a call of its own
- `description` (null|string): a new description, up to 150 characters; omit to leave it alone. Pass an empty string to clear it
- `display_name` (null|string): a new name, 1 to 128 characters; omit to leave it alone
- `dry_run` (boolean): return the patch body and its mask without applying them
- `space_id` (string, required): the space to edit, spaces/{id}

Output parameters:

- `audience` (null|string): the target audience that was set, private when the space was made private, or null when the call left it alone
- `description` (null|string): the description that was set, or null when the call left it alone
- `display_name` (null|string): the name that was set, or null when the call left it alone
- `dry_run` (boolean): true when nothing was changed
- `rendered_payload` (null|object): on a dry run, the exact patch body; null on a real edit
- `space_id` (string): the space that was edited
- `update_mask` (null|string): which top-level fields the patch targeted

### `update_space_notification_setting` (~132 tokens)

Change what Chat tells you about a space, or mute it. Pass either setting or both; whatever you leave out is left alone. Affects you and nobody else.

Input parameters:

- `dry_run` (boolean): return the request body without changing anything
- `mute_setting` (string): MUTED or UNMUTED; omit to leave it alone. MUTED silences the space whatever the other setting says
- `notification_setting` (string): ALL, MAIN_CONVERSATIONS, FOR_YOU or OFF; omit to leave it alone
- `space_id` (string, required): the space, spaces/{id}

Output parameters:

- `dry_run` (boolean): true when nothing was changed
- `mute_setting` (string): MUTED silences the space whatever notification_setting says; UNMUTED respects it
- `name` (string): the setting's own resource name
- `notification_setting` (string): ALL for every new thread and mention, MAIN_CONVERSATIONS for the main conversation only, FOR_YOU for mentions and followed threads, OFF for none, or NOTIFICATION_SETTING_UNSPECIFIED for a value this…
- `rendered_payload` (null|object): on a dry run, the exact body that would have been sent; null on a real change

### `upload_attachment` (~212 tokens)

Upload a local file to a Chat space and get back the token that attaches it. Post it with send_message's attachment_upload_token, in the same space; nobody sees the file until then. The file has to be inside the server's local directory, and Google's limit is 200 MB. Set dry_run to check the file and see what would be sent. This needs the server to have been started with GCM_LOCAL_DIR.

Input parameters:

- `dry_run` (boolean): report the file and the request metadata without uploading; call again without it to upload
- `file_name` (string): the name the file gets in Chat, with its extension. Omit to keep the name it has on disk
- `local_path` (string, required): the file to send, inside the server's local directory. A bare name is taken as being in that directory; a path outside it is refused
- `space_id` (string, required): the space the file is for, spaces/{id}. The token only works for this space

Output parameters:

- `bytes` (integer): the file's size on disk
- `content_type` (string): the MIME type this server derived from the extension, or empty when it could not
- `dry_run` (boolean): true when nothing was uploaded
- `file_name` (string): the name the file has in Chat
- `rendered_payload` (null|object): on a dry run, the metadata that would go with the file; null on a real upload
- `upload_token` (null|string): pass this to send_message as attachment_upload_token. Null after a dry run, because nothing was uploaded

### `whoami` (~55 tokens)

Return the authenticated Google user's identity (subject id, email, display name). Useful as a first-call smoke test, and for resolving who "me" is before filtering messages by sender. Reads from the OpenID Connect userinfo endpoint.

Output parameters:

- `display_name` (string): the account's display name
- `email` (string): the account's email address
- `picture_url` (string): URL of the account's profile picture
- `user_sub` (string): the account's stable Google subject id

## Diagnostics

Captured diagnostic sections: Provenance. The full working is on the page: https://verifymcp.io/servers/mmedum-google-chat-mcp/https-github-com-mmedum-google-chat-mcp-releases-download-v2-3-1-google-chat-mcp#diagnostics

## Score history

- 2026-10-24: 63
- 2026-10-23: 62
- 2026-10-22: 63
- 2026-10-21: 63
- 2026-10-20: 62
- 2026-10-19: 62
- 2026-10-18: 61
- 2026-10-17: 61
- 2026-10-16: 61
- 2026-10-15: 60
- 2026-10-14: 60
- 2026-10-13: 19
- 2026-10-12: 18
- 2026-10-11: 8
- 2026-10-07: 57
- 2026-10-04: 55
- 2026-10-03: 55
- 2026-10-02: 54
- 2026-10-01: 54
- 2026-09-30: 53
- 2026-09-29: 53
- 2026-09-28: 41
- 2026-09-27: 41
- 2026-09-26: 41

## Common questions

### What is the io.github.mmedum/google-chat-mcp server?

io.github.mmedum/google-chat-mcp is listed in the public MCP registry as io.github.mmedum/google-chat-mcp. Google Chat as MCP tools: read, search and write to your spaces, direct messages and sidebar. This page covers its MCPB bundle (https://github.com/mmedum/google-chat-mcp/releases/download/v6.1.0/google-chat-mcp_6.1.0.mcpb).

### Is the io.github.mmedum/google-chat-mcp server safe to use?

io.github.mmedum/google-chat-mcp scores 63 out of 100 on VerifyMCP. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the io.github.mmedum/google-chat-mcp server expose?

io.github.mmedum/google-chat-mcp exposes 49 tools: add_member, add_reaction, create_custom_emoji, create_group_chat, create_section, and 44 more. Their descriptions and schemas cost roughly 7,863 tokens of context every time the server is loaded.

### What licence is the io.github.mmedum/google-chat-mcp server under?

io.github.mmedum/google-chat-mcp declares the Apache-2.0 licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.

## Links

- Repository: https://github.com/mmedum/google-chat-mcp
- Changelog RSS feed: https://verifymcp.io/servers/mmedum-google-chat-mcp/https-github-com-mmedum-google-chat-mcp-releases-download-v2-3-1-google-chat-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/mmedum-google-chat-mcp/https-github-com-mmedum-google-chat-mcp-releases-download-v2-3-1-google-chat-mcp.json
- HTML version of this page: https://verifymcp.io/servers/mmedum-google-chat-mcp/https-github-com-mmedum-google-chat-mcp-releases-download-v2-3-1-google-chat-mcp
