#20928: mattermost: add readMessages action for channel history
channel: mattermost
gateway
size: M
Cluster:
Mattermost Integration Enhancements
## 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
#12468: feat(mattermost): add read, search, and channel-list actions
by adamsbytes · 2026-02-09
88.6%
#16570: feat(mattermost): add replyToMode threading support
by FBartos · 2026-02-14
79.6%
#22216: fix(slack): enable thread reply reading in slack extension plugin
by lan17 · 2026-02-20
77.2%
#19274: feat(mattermost): enable threaded replies in channels
by rockinyp · 2026-02-17
76.5%
#19265: feat(mattermost): Add directory adapter for channel/user name resol...
by oskarmodig · 2026-02-17
76.4%
#22075: mattermost: honor account requireMention override
by armindocachada · 2026-02-20
75.7%
#14367: feat(telegram): add message read via inbound message store
by michaelquinlan88 · 2026-02-12
75.6%
#16622: fix(mattermost): record pending history for messages dropped by gro...
by oskarmodig · 2026-02-14
75.5%
#11491: feat(slack): allow agents to resolve channel IDs to names and list ...
by Lukavyi · 2026-02-07
75.2%
#10027: Mattermost: fix attachment downloads (GET + private-network hosts)
by transportrefer · 2026-02-06
74.4%