← Back to PRs

#20928: mattermost: add readMessages action for channel history

by hubertusgbecker open 2026-02-19 13:09 View on GitHub →
channel: mattermost gateway size: M
## Summary - **Problem:** The Mattermost extension only supports the `react` message action. It cannot read channel history, which blocks features like channel summarization and digest generation. - **Why it matters:** Slack and Discord both support `readMessages`, making Mattermost a second-class citizen. Users relying on Mattermost cannot use the agent's summarization capabilities. - **What changed:** Added `readMessages` (mapped from the `read` action name) support to the Mattermost plugin — new `fetchMattermostChannelPosts` client function, a `readMattermostMessages` helper with username resolution, and wired the `read` action into the plugin's `listActions`/`supportsAction`/`handleAction` adapter. - **What did NOT change (scope boundary):** No changes to core message-action-runner, channel-tools, or any other channel plugin. The existing `react` action behavior is preserved. No config schema changes — `actions.messages` gate follows the same pattern as `actions.reactions`. ## Change Type (select all) - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Docs - [ ] Security hardening - [ ] Chore/infra ## Scope (select all touched areas) - [ ] Gateway / orchestration - [ ] Skills / tool execution - [ ] Auth / tokens - [ ] Memory / storage - [x] Integrations - [ ] API / contracts - [ ] UI / DX - [ ] CI/CD / infra ## Linked Issue/PR - Related: Mattermost readMessages parity with Slack/Discord ## User-visible / Behavior Changes - Mattermost channel plugin now advertises the `read` action when at least one account has messaging enabled (default: enabled). - Agents can use `message` tool with `action: "read"` + `channelId` to fetch recent posts from any Mattermost channel the bot has access to. - The `actions.messages` config gate (per-account or base) controls whether reads are enabled (default: `true`), consistent with the existing `actions.reactions` pattern. ## Security Impact (required) - New permissions/capabilities? `Yes` — the bot can now read channel history via Mattermost REST API (GET `/channels/{channelId}/posts`). This is limited to channels the bot token already has access to. - Secrets/tokens handling changed? `No` — uses the same `botToken` already configured for the account. - New/changed network calls? `Yes` — new GET request to Mattermost `/api/v4/channels/{channelId}/posts` and `/api/v4/users/{userId}` (for username resolution). - Command/tool execution surface changed? `No` - Data access scope changed? `Yes` — agents can now read Mattermost channel messages (previously only reactions were supported). - Risk + mitigation: The `read` action is gated by `actions.messages` config (default `true`). Operators can disable it per-account or globally by setting `channels.mattermost.actions.messages: false`. The bot can only read channels it has been added to — no privilege escalation. ## Repro + Verification ### Environment - OS: macOS (dev), Linux x86_64/Docker (production on Synology DiskStation) - Runtime/container: Node 22+, Docker 24.0.2 - Model/provider: litellm/gpt-5-mini via LiteLLM proxy - Integration/channel: Mattermost (self-hosted) - Relevant config: `channels.mattermost.enabled: true`, default account with botToken + baseUrl ### Steps 1. Configure Mattermost with a bot token and base URL 2. Send agent a message: "summarize #digest channel" 3. Agent uses `message` tool with `action: "read"`, `channelId: "<digest-channel-id>"` ### Expected - Agent reads recent posts from the channel and returns a summary ### Actual - Before this PR: `Message action read not supported for channel mattermost` - After this PR: Agent successfully reads channel posts and summarizes them ## Evidence - [x] Failing test/log before + passing after - [ ] Trace/log snippets - [ ] Screenshot/recording - [ ] Perf numbers (if relevant) All 30 existing Mattermost extension tests pass (5 test files). The existing `react` action tests continue to pass unchanged. Build (`pnpm build`), format (`pnpm format`), and lint (`pnpm check`) all pass clean. ## Human Verification (required) - Verified scenarios: Local build + all Mattermost extension tests pass post-rebase. Format and lint gates clean. - Edge cases checked: Missing channelId throws descriptive error; `actions.messages: false` disables reads; accounts without botToken/baseUrl are excluded from capability advertisement. - What you did **not** verify: Live end-to-end test against a running Mattermost instance (pending Docker rebuild on target host). ## Compatibility / Migration - Backward compatible? `Yes` — existing configs work unchanged. The `read` action is additive; `react` behavior is preserved. - Config/env changes? `No` — `actions.messages` defaults to `true` (same pattern as `actions.reactions`). - Migration needed? `No` ## Failure Recovery (if this breaks) - How to disable/revert this change quickly: Set `channels.mattermost.actions.messages: false` in config to disable reads without reverting code. - Files/config to restore: Revert the 3 changed files in `extensions/mattermost/src/`. - Known bad symptoms reviewers should watch for: Unexpected errors when agent tries to read Mattermost channels; increased API calls to Mattermost server (username resolution per read). ## Risks and Mitigations - Risk: Username resolution makes N+1 API calls (one per unique user in fetched posts). - Mitigation: In-call username cache deduplicates lookups within a single read. For typical channel reads (60 posts), this results in far fewer API calls than posts. A persistent cache could be added later if needed. - Risk: Large channel reads could return substantial data to the agent context. - Mitigation: Default limit is 60 posts (Mattermost API default), capped at 200. The agent can specify a lower limit. <!-- greptile_comment --> <h3>Greptile Summary</h3> Adds `readMessages` action to Mattermost plugin, bringing feature parity with Slack and Discord for channel history retrieval. The implementation follows existing patterns with config-gated access and username resolution. **Key changes:** - New `fetchMattermostChannelPosts` client function in `client.ts` with pagination support (before/after/limit) - New `readMattermostMessages` helper in `read.ts` with in-call username caching to reduce N+1 API calls - Wired `read` action into `listActions`/`supportsAction`/`handleAction` adapter with `actions.messages` config gate (default: true) **Issue found:** - Config schema missing `messages` field in `actions` object - will cause runtime validation failures when users try to configure `actions.messages: false` <h3>Confidence Score: 3/5</h3> - Safe to merge after fixing the config schema - the missing `messages` field will cause validation errors - Score reflects one blocking schema bug that must be fixed. The implementation is otherwise solid - follows established patterns from Slack/Discord, includes proper config gating, and handles username resolution efficiently. However, the missing `messages` field in the config schema will cause runtime validation failures when users configure the feature. - Pay close attention to `extensions/mattermost/src/config-schema.ts` - must add `messages` field to actions schema before merge <sub>Last reviewed commit: 25f51a1</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs