{"_id":"@bryanberger/mattermost-mcp","_rev":"5-3bd2e58e5f4ea46b8066c8d02dafd63c","name":"@bryanberger/mattermost-mcp","dist-tags":{"latest":"0.5.0"},"versions":{"0.2.0":{"name":"@bryanberger/mattermost-mcp","version":"0.2.0","keywords":["mcp","model-context-protocol","mattermost","chatops","stdio","ai-tools","claude"],"author":{"name":"Bryan Berger","email":"contact@bryanberger.dev"},"license":"MIT","_id":"@bryanberger/mattermost-mcp@0.2.0","maintainers":[{"name":"bryanberger","email":"bryan.berger98@gmail.com"}],"homepage":"https://github.com/BryanBerger98/mattermost-mcp#readme","bugs":{"url":"https://github.com/BryanBerger98/mattermost-mcp/issues"},"bin":{"mattermost-mcp":"dist/index.js"},"dist":{"shasum":"1709cf453b1304426b33c12d55cc53ed3d0083ae","tarball":"https://registry.npmjs.org/@bryanberger/mattermost-mcp/-/mattermost-mcp-0.2.0.tgz","fileCount":48,"integrity":"sha512-/IZLfY5Kekn2YgzR+ARH0GwipFW48La3QDufpyp55WA02glyak8cETWPl5WCROyXxgnb2/a9pbG/jZLSwNTBpg==","signatures":[{"sig":"MEQCIF6Xtm7WY0cMYroyETnfCQWkQRVwB9kXUdzsOUBTqKLZAiAs3eWheC837U5WS/cYb9nn5CudOECiYQfkUG3XjaS7UA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":140595},"type":"module","engines":{"node":">=20"},"gitHead":"e31bc24a4f85915e21ae469aff8046f79c9fbbc7","scripts":{"dev":"tsx src/index.ts","lint":"eslint . && prettier --check .","test":"vitest run --passWithNoTests","build":"tsc","start":"node dist/index.js","format":"prettier --write .","release":"npm run build && changeset publish","version":"changeset version","changeset":"changeset","test:watch":"vitest","test:integration":"MM_INTEGRATION=1 vitest run src/integration"},"_npmUser":{"name":"bryanberger","email":"bryan.berger98@gmail.com"},"repository":{"url":"git+https://github.com/BryanBerger98/mattermost-mcp.git","type":"git"},"_npmVersion":"11.13.0","description":"MCP server exposing the Mattermost REST API v4 as tools (self-hosted instances).","directories":{},"_nodeVersion":"20.19.6","dependencies":{"zod":"^3.23","@mattermost/client":"^11.6","zod-to-json-schema":"^3.25.2","@modelcontextprotocol/sdk":"^1.29"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.16","eslint":"^9.9","vitest":"^2.0","prettier":"^3.3","@eslint/js":"^9.9","typescript":"^5.5","@types/node":"^20.14","@changesets/cli":"^2.31.0","typescript-eslint":"^8.0","eslint-config-prettier":"^9.1","@changesets/changelog-github":"^0.7.0"},"_npmOperationalInternal":{"tmp":"tmp/mattermost-mcp_0.2.0_1780324005948_0.14222818138511828","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@bryanberger/mattermost-mcp","version":"0.2.1","keywords":["mcp","model-context-protocol","mattermost","chatops","stdio","ai-tools","claude"],"author":{"name":"Bryan Berger","email":"contact@bryanberger.dev"},"license":"MIT","_id":"@bryanberger/mattermost-mcp@0.2.1","maintainers":[{"name":"bryanberger","email":"bryan.berger98@gmail.com"}],"homepage":"https://github.com/BryanBerger98/mattermost-mcp#readme","bugs":{"url":"https://github.com/BryanBerger98/mattermost-mcp/issues"},"bin":{"mattermost-mcp":"dist/index.js"},"dist":{"shasum":"d2c5779904325395abb21233bf6d22191b7fe9f0","tarball":"https://registry.npmjs.org/@bryanberger/mattermost-mcp/-/mattermost-mcp-0.2.1.tgz","fileCount":48,"integrity":"sha512-LeMXJqurdnvF/yI7aCzOICHjboxM70RehLwlsUhrk/wkdwmpzCmNzmput7KabJiD5forJCUFi65oR9dBKA6xJA==","signatures":[{"sig":"MEYCIQC3TKJiRJNIIQln17VUJPkZ6R1lnlQy/3H2djVIzWiNbAIhAKwxizDVF6OboDdNIaawicK9a3QzDfmkt2vTh6gmutJP","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bryanberger%2fmattermost-mcp@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":140571},"type":"module","engines":{"node":">=20"},"gitHead":"53f1db94a972e8087ad77266ed9e30a4ab6624ac","scripts":{"dev":"tsx src/index.ts","lint":"eslint . && prettier --check .","test":"vitest run --passWithNoTests","build":"tsc","start":"node dist/index.js","format":"prettier --write .","release":"npm run build && changeset publish","version":"changeset version","changeset":"changeset","test:watch":"vitest","test:integration":"MM_INTEGRATION=1 vitest run src/integration"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:26b92099-537f-472e-8db5-f92004c87b76"}},"repository":{"url":"git+https://github.com/BryanBerger98/mattermost-mcp.git","type":"git"},"_npmVersion":"11.16.0","description":"MCP server exposing the Mattermost REST API v4 as tools (self-hosted instances).","directories":{},"_nodeVersion":"22.22.3","dependencies":{"zod":"^3.23","@mattermost/client":"^11.6","zod-to-json-schema":"^3.25.2","@modelcontextprotocol/sdk":"^1.29"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.16","eslint":"^9.9","vitest":"^2.0","prettier":"^3.3","@eslint/js":"^9.9","typescript":"^5.5","@types/node":"^20.14","@changesets/cli":"^2.31.0","typescript-eslint":"^8.0","eslint-config-prettier":"^9.1","@changesets/changelog-github":"^0.7.0"},"_npmOperationalInternal":{"tmp":"tmp/mattermost-mcp_0.2.1_1780325380110_0.8403626922945999","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@bryanberger/mattermost-mcp","version":"0.3.0","keywords":["mcp","model-context-protocol","mattermost","chatops","stdio","ai-tools","claude"],"author":{"name":"Bryan Berger","email":"contact@bryanberger.dev"},"license":"MIT","_id":"@bryanberger/mattermost-mcp@0.3.0","maintainers":[{"name":"bryanberger","email":"bryan.berger98@gmail.com"}],"homepage":"https://github.com/BryanBerger98/mattermost-mcp#readme","bugs":{"url":"https://github.com/BryanBerger98/mattermost-mcp/issues"},"bin":{"mattermost-mcp":"dist/index.js"},"dist":{"shasum":"a37bcae28ec55949e9316eccf7f1389d5fa639e5","tarball":"https://registry.npmjs.org/@bryanberger/mattermost-mcp/-/mattermost-mcp-0.3.0.tgz","fileCount":69,"integrity":"sha512-tL6+DqwnRXZXkTWrAJMg7m1n5t45kn4+cJhbnHOG7Fp1rYteko5QQH2CStQ/s+gXim6qBwvbGSCTmxCsM8Po+g==","signatures":[{"sig":"MEUCIQDP37Dz3lKNO0YqG8L6KgkLpra5Rk89fi60WAegdTrd0AIgfuVpMgMhBY4UxcTqcqMb15Bf0LVSRtSu0lM8Z96vLrI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bryanberger%2fmattermost-mcp@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":170644},"type":"module","engines":{"node":">=20"},"gitHead":"aea0122ac9cdea045eaccaaab02ca13117b7859c","scripts":{"dev":"tsx src/index.ts","lint":"eslint . && prettier --check .","test":"vitest run --passWithNoTests","build":"tsc","start":"node dist/index.js","format":"prettier --write .","release":"npm run build && changeset publish","version":"changeset version","changeset":"changeset","test:watch":"vitest","test:integration":"MM_INTEGRATION=1 vitest run src/integration"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:26b92099-537f-472e-8db5-f92004c87b76"}},"repository":{"url":"git+https://github.com/BryanBerger98/mattermost-mcp.git","type":"git"},"_npmVersion":"11.16.0","description":"MCP server exposing the Mattermost REST API v4 as tools (self-hosted instances).","directories":{},"_nodeVersion":"22.22.3","dependencies":{"zod":"^3.23","@mattermost/client":"^11.6","zod-to-json-schema":"^3.25.2","@modelcontextprotocol/sdk":"^1.29"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.16","eslint":"^9.9","vitest":"^2.0","prettier":"^3.3","@eslint/js":"^9.9","typescript":"^5.5","@types/node":"^20.14","@changesets/cli":"^2.31.0","typescript-eslint":"^8.0","eslint-config-prettier":"^9.1","@changesets/changelog-github":"^0.7.0"},"_npmOperationalInternal":{"tmp":"tmp/mattermost-mcp_0.3.0_1780327956181_0.1716541246699581","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@bryanberger/mattermost-mcp","version":"0.4.0","keywords":["mcp","model-context-protocol","mattermost","chatops","stdio","ai-tools","claude"],"author":{"name":"Bryan Berger","email":"contact@bryanberger.dev"},"license":"MIT","_id":"@bryanberger/mattermost-mcp@0.4.0","maintainers":[{"name":"bryanberger","email":"bryan.berger98@gmail.com"}],"homepage":"https://github.com/BryanBerger98/mattermost-mcp#readme","bugs":{"url":"https://github.com/BryanBerger98/mattermost-mcp/issues"},"bin":{"mattermost-mcp":"dist/index.js"},"dist":{"shasum":"541d47673584591fd02fefe7c6e9bb3055699ed1","tarball":"https://registry.npmjs.org/@bryanberger/mattermost-mcp/-/mattermost-mcp-0.4.0.tgz","fileCount":72,"integrity":"sha512-XUxP6kZJaFks1c1D+BhSkDZV2yw8Njyuc9m/E6jscs0Rg9IxeoPWaT6wWg3BSUWGNnObuhISAqsnZvWiV+mEtw==","signatures":[{"sig":"MEUCICuh4BoCVfe/2FfcGmbECpYNn6jAN6uzN7mtljIOL4CjAiEAx8sZskA6COh8V6vO/QW0wuuVkhUvn1rpzG0qHC7b5Mk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bryanberger%2fmattermost-mcp@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":186113},"type":"module","engines":{"node":">=20"},"gitHead":"bce2abc35483c6d89c49df2c093a0da23d4f32cf","scripts":{"dev":"tsx src/index.ts","lint":"eslint . && prettier --check .","test":"vitest run --passWithNoTests","build":"tsc","start":"node dist/index.js","format":"prettier --write .","release":"npm run build && changeset publish","version":"changeset version","changeset":"changeset","test:watch":"vitest","test:integration":"MM_INTEGRATION=1 vitest run src/integration"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:26b92099-537f-472e-8db5-f92004c87b76"}},"repository":{"url":"git+https://github.com/BryanBerger98/mattermost-mcp.git","type":"git"},"_npmVersion":"11.16.0","description":"MCP server exposing the Mattermost REST API v4 as tools (self-hosted instances).","directories":{},"_nodeVersion":"22.22.3","dependencies":{"zod":"^3.23","puppeteer-core":"^24.43.1","@mattermost/client":"^11.6","zod-to-json-schema":"^3.25.2","@modelcontextprotocol/sdk":"^1.29"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.16","eslint":"^9.9","vitest":"^2.0","prettier":"^3.3","@eslint/js":"^9.9","typescript":"^5.5","@types/node":"^20.14","@changesets/cli":"^2.31.0","typescript-eslint":"^8.0","eslint-config-prettier":"^9.1","@changesets/changelog-github":"^0.7.0"},"_npmOperationalInternal":{"tmp":"tmp/mattermost-mcp_0.4.0_1780332147819_0.9082295438646819","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@bryanberger/mattermost-mcp","version":"0.5.0","description":"MCP server exposing the Mattermost REST API v4 as tools (self-hosted instances).","type":"module","license":"MIT","author":{"name":"Bryan Berger","email":"contact@bryanberger.dev"},"homepage":"https://github.com/BryanBerger98/mattermost-mcp#readme","repository":{"type":"git","url":"git+https://github.com/BryanBerger98/mattermost-mcp.git"},"bugs":{"url":"https://github.com/BryanBerger98/mattermost-mcp/issues"},"keywords":["mcp","model-context-protocol","mattermost","chatops","stdio","ai-tools","claude"],"bin":{"mattermost-mcp":"dist/index.js"},"publishConfig":{"access":"public"},"engines":{"node":">=20"},"scripts":{"build":"tsc","dev":"tsx src/index.ts","start":"node dist/index.js","lint":"eslint . && prettier --check .","format":"prettier --write .","test":"vitest run --passWithNoTests","test:watch":"vitest","test:integration":"MM_INTEGRATION=1 vitest run src/integration","changeset":"changeset","version":"changeset version","release":"npm run build && changeset publish"},"dependencies":{"@mattermost/client":"^11.6","@modelcontextprotocol/sdk":"^1.29","puppeteer-core":"^24.43.1","zod":"^3.23","zod-to-json-schema":"^3.25.2"},"devDependencies":{"@changesets/changelog-github":"^0.7.0","@changesets/cli":"^2.31.0","@eslint/js":"^9.9","@types/node":"^20.14","eslint":"^9.9","eslint-config-prettier":"^9.1","prettier":"^3.3","tsx":"^4.16","typescript":"^5.5","typescript-eslint":"^8.0","vitest":"^2.0"},"gitHead":"6e985e00c8eee678cbcaef18231921c8076d399e","_id":"@bryanberger/mattermost-mcp@0.5.0","_nodeVersion":"22.22.3","_npmVersion":"11.16.0","dist":{"integrity":"sha512-3eaiA4YJP3TLLVPM4bnV0bgKqnYS9qxxfzd8fx8ydVBnrQc33YSWfQqT27oJIirYwfwNBw8qCrqvYs44d3Efag==","shasum":"b0c6bd10afbb56418781fee4d301ba092acb85a5","tarball":"https://registry.npmjs.org/@bryanberger/mattermost-mcp/-/mattermost-mcp-0.5.0.tgz","fileCount":75,"unpackedSize":204911,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bryanberger%2fmattermost-mcp@0.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQD07sjylc49/nrgdMQx+kN1OBdHDJSXxfoO9+8hb58JvAIgMLvGHwTAbCxFhfJG1ESWRtWeenVeMRUEm+G3eTabfJg="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:26b92099-537f-472e-8db5-f92004c87b76"}},"directories":{},"maintainers":[{"name":"bryanberger","email":"bryan.berger98@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mattermost-mcp_0.5.0_1780333486732_0.7295552505330396"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-01T14:26:45.711Z","modified":"2026-06-01T17:04:47.227Z","0.2.0":"2026-06-01T14:26:46.104Z","0.2.1":"2026-06-01T14:49:40.264Z","0.3.0":"2026-06-01T15:32:36.334Z","0.4.0":"2026-06-01T16:42:28.023Z","0.5.0":"2026-06-01T17:04:46.936Z"},"bugs":{"url":"https://github.com/BryanBerger98/mattermost-mcp/issues"},"author":{"name":"Bryan Berger","email":"contact@bryanberger.dev"},"license":"MIT","homepage":"https://github.com/BryanBerger98/mattermost-mcp#readme","keywords":["mcp","model-context-protocol","mattermost","chatops","stdio","ai-tools","claude"],"repository":{"type":"git","url":"git+https://github.com/BryanBerger98/mattermost-mcp.git"},"description":"MCP server exposing the Mattermost REST API v4 as tools (self-hosted instances).","maintainers":[{"name":"bryanberger","email":"bryan.berger98@gmail.com"}],"readme":"# mattermost-mcp\n\nA Node.js 20 / TypeScript MCP server over **stdio** that wraps the official\n[`@mattermost/client`](https://github.com/mattermost/mattermost/tree/master/webapp/packages/client)\nClient4 (REST v4). It authenticates to a **self-hosted** Mattermost instance and exposes\n**34 tools** across messaging, channels/teams, users/presence, and file operations. Safe-by-default\nvia a configurable guardrail layer; all output goes to stdout (the MCP channel) and all logging goes\nto stderr.\n\n> **Self-hosted only.** Mattermost Cloud does not expose the REST v4 endpoints used here; you need\n> a self-managed Mattermost server (any recent version supporting REST v4).\n\n## Features\n\n- **3 authentication modes** — Personal Access Token (default), username/password (+MFA), OAuth2\n  (authorization-code + PKCE S256 with transparent token refresh).\n- **34 tools** across 4 domains — messaging (13), channels & teams (12), users & presence (6),\n  files (3).\n- **Safe by default** — read-only mode (`MM_READ_ONLY`), destructive-action gate\n  (`MM_ALLOW_DESTRUCTIVE`), team/channel allowlists, and per-call `confirm: true` requirement for\n  destructive tools.\n- **Resilience** — configurable request timeout, retry with exponential back-off + jitter on `429` /\n  `5xx` / network errors.\n- **Strict validation** — every tool input is validated with a Zod schema before any API call.\n  Mattermost errors are surfaced verbatim (status code + message).\n\n## Requirements\n\n- Node.js ≥ 20\n- A self-hosted Mattermost server with a user account and credentials (PAT, login/password, or an\n  OAuth2 application)\n\n## Install\n\n### Global (recommended)\n\n```bash\nnpm i -g @bryanberger/mattermost-mcp\nmattermost-mcp login        # interactive: server URL + auth, saved to the config dir\nmattermost-mcp status       # verify: prints the authenticated identity\n```\n\n`login` validates the credentials against the server and writes them (0600) under\n`$XDG_CONFIG_HOME/mattermost-mcp` (or `~/.config/mattermost-mcp`). The MCP server then picks them up\nautomatically — no env vars required. See [CLI](#cli) and [Authenticate with `login`](#authenticate-with-login).\n\n### From source\n\n```bash\nnpm install\nnpm run build\n# Binary is now at dist/index.js (also available as mattermost-mcp via the bin field)\n```\n\n## CLI\n\nThe `mattermost-mcp` binary is both the MCP server and a small management CLI:\n\n| Command                         | Description                                                             |\n| ------------------------------- | ----------------------------------------------------------------------- |\n| `mattermost-mcp`                | Start the MCP server on stdio (default — this is what MCP clients run). |\n| `mattermost-mcp login`          | Interactive auth wizard; validates and saves credentials.               |\n| `mattermost-mcp login --gitlab` | Browser SSO login (GitLab/SAML) — no admin or PAT required.             |\n| `mattermost-mcp status`         | Authenticate with the resolved config and print the current identity.   |\n| `mattermost-mcp logout`         | Remove saved credentials (and the matching OAuth token cache).          |\n| `mattermost-mcp --help`         | Usage. `--version` prints the version.                                  |\n\n## Authenticate with `login`\n\n```text\n$ mattermost-mcp login\nMattermost server URL (e.g. https://mm.example.com): https://mattermost.example.com\nAuthentication mode (↑/↓ to move, Enter to select):\n› pat           paste a Personal Access Token\n  password      username/email + password (+ MFA)\n  oauth2        OAuth2 app + browser consent\n  gitlab / SSO  browser login via GitLab/SAML — no admin\nPersonal Access Token: ********\n✓ Logged in as @alice on https://mattermost.example.com\n  Saved to ~/.config/mattermost-mcp/credentials.json (mode: pat, 0600)\n```\n\nThe mode picker is keyboard-navigable (arrow keys / `j`·`k`, digits to jump, Enter to confirm). When\ninput is not a TTY it falls back to a numbered prompt.\n\n- **pat** — saves the token as-is.\n- **password** — exchanges your password for a **session token** and saves _that_ (the password is\n  never written to disk); re-run `login` when the session expires.\n- **oauth2** — runs the browser consent flow and caches the OAuth tokens (refreshed transparently).\n- **gitlab / SSO** — see below; also selectable directly with `mattermost-mcp login --gitlab`.\n\n### Browser SSO login (GitLab / SAML)\n\nIf your server's only login is an external IdP (e.g. GitLab) **and you are not an admin**, both PATs\nand OAuth2 apps may be unavailable — they require server settings only an admin can enable. Use the\nbrowser SSO login instead:\n\n```text\n$ mattermost-mcp login --gitlab\nMattermost server URL: https://mattermost.example.com\nOpening a browser window. Complete the GitLab (or other SSO) login there.\n✓ Logged in as @alice on https://mattermost.example.com\n  Saved to ~/.config/mattermost-mcp/credentials.json (mode: pat — browser SSO session token, 0600)\n```\n\nIt opens a browser at `{server}/login`, waits while you complete the SSO login in that window, then\nreads the resulting `MMAUTHTOKEN` session cookie and saves it as a token. The flag is\nprovider-agnostic (`--sso` is an alias), and `gitlab / SSO` is also offered in the `login` menu.\n\n- Uses your **default browser** when it is Chromium-based (Chrome, Chromium, Brave, Edge, Opera,\n  Vivaldi, Arc, Dia…); otherwise the first installed Chromium engine it finds. Override with\n  `MM_CHROME_PATH=/path/to/browser` (puppeteer-core can only drive Chromium engines — not Safari or\n  Firefox).\n- The captured token is a **session token** — it expires with the server's SSO session length. Re-run\n  `mattermost-mcp login --gitlab` when calls start returning `401`.\n- Cleanest long-term fix: ask an admin to enable Personal Access Tokens, then use `login` (pat).\n\n## Configuration\n\nCredentials come from two sources, in order of precedence:\n\n1. **Environment variables** (`MM_*`) — always win; ideal for CI and the `examples/` MCP client configs.\n2. **Saved `login` credentials** — the baseline when the matching env vars are absent.\n\nIn development you can place env vars in a `.env` file in the project root and export them before\nrunning; in production pass them directly to the process. A fully annotated `.env.example` ships in\nthe repository. Every setting below is also configurable via env.\n\n### Environment Variables\n\n#### Connection\n\n| Variable | Required | Default | Description                                                                               |\n| -------- | -------- | ------- | ----------------------------------------------------------------------------------------- |\n| `MM_URL` | **yes**  | —       | Server root URL, no trailing slash, no `/api/v4` (e.g. `https://mattermost.example.com`). |\n\n#### Authentication\n\n| Variable            | Required        | Default                          | Description                                                                                                  |\n| ------------------- | --------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------ |\n| `MM_AUTH_MODE`      | no              | `pat`                            | One of `pat \\| password \\| oauth2`.                                                                          |\n| `MM_TOKEN`          | when `pat`      | —                                | Personal Access Token (Bearer; no expiry). Enable in System Console → Integrations → Personal Access Tokens. |\n| `MM_LOGIN_ID`       | when `password` | —                                | Username or email.                                                                                           |\n| `MM_PASSWORD`       | when `password` | —                                | Password.                                                                                                    |\n| `MM_MFA_TOKEN`      | no              | —                                | MFA one-time code (only if the account enforces MFA).                                                        |\n| `MM_CLIENT_ID`      | when `oauth2`   | —                                | OAuth2 app client id (register in System Console → Integrations → OAuth 2.0 Applications).                   |\n| `MM_CLIENT_SECRET`  | when `oauth2`   | —                                | OAuth2 app client secret.                                                                                    |\n| `MM_OAUTH_REDIRECT` | no              | `http://127.0.0.1:7000/callback` | Loopback redirect URI (must start with `http://` or `https://`).                                             |\n\n#### Guardrails\n\n| Variable               | Required | Default          | Description                                                                                                 |\n| ---------------------- | -------- | ---------------- | ----------------------------------------------------------------------------------------------------------- |\n| `MM_READ_ONLY`         | no       | `false`          | `true` disables every write/destructive tool (they hard-refuse at call time; still listed in `tools/list`). |\n| `MM_ALLOW_DESTRUCTIVE` | no       | `false`          | Gates the 💥 destructive tools; they also require `confirm: true` per call.                                 |\n| `MM_TEAM_ALLOWLIST`    | no       | _(unrestricted)_ | CSV of team ids; actions targeting teams outside this list are refused.                                     |\n| `MM_CHANNEL_ALLOWLIST` | no       | _(unrestricted)_ | CSV of channel ids; actions targeting channels outside this list are refused.                               |\n| `MM_MAX_MESSAGE_LEN`   | no       | `16383`          | Reject messages longer than this (Unicode code points) before sending.                                      |\n\n#### Resilience\n\n| Variable                | Required | Default | Description                                                                   |\n| ----------------------- | -------- | ------- | ----------------------------------------------------------------------------- |\n| `MM_REQUEST_TIMEOUT_MS` | no       | `30000` | Per-request timeout in ms (`0` disables).                                     |\n| `MM_MAX_RETRIES`        | no       | `3`     | Retries on `429` / `5xx` / network errors with exponential back-off + jitter. |\n| `MM_RETRY_BASE_MS`      | no       | `500`   | Back-off base delay in ms.                                                    |\n\n## Authentication Modes\n\n### pat (default, recommended)\n\nCreate a Personal Access Token in **System Console → Integrations → Personal Access Tokens**, then:\n\n```bash\nMM_AUTH_MODE=pat\nMM_TOKEN=your-personal-access-token\n```\n\nNo expiry; revocable at any time; simplest setup.\n\n### password\n\n```bash\nMM_AUTH_MODE=password\nMM_LOGIN_ID=your-username-or-email\nMM_PASSWORD=your-password\n# MM_MFA_TOKEN=123456   # only if the account enforces MFA\n```\n\nThe server calls `POST /users/login`, captures the session token from the `Token` response header,\nand automatically re-authenticates on a `401`.\n\n### oauth2\n\nRegister a **confidential** OAuth2 application in **System Console → Integrations → OAuth 2.0\nApplications** with a loopback redirect URI (`http://127.0.0.1:7000/callback` by default), then:\n\n```bash\nMM_AUTH_MODE=oauth2\nMM_CLIENT_ID=your-client-id\nMM_CLIENT_SECRET=your-client-secret\n# MM_OAUTH_REDIRECT=http://127.0.0.1:7000/callback   # optional override\n```\n\nOn first run the server opens a browser for the authorization-code + PKCE S256 flow. Tokens are\ncached under `$XDG_CONFIG_HOME/mattermost-mcp` (or `~/.config/mattermost-mcp`) with `0600`\npermissions and refreshed transparently thereafter.\n\n> **Note:** Mattermost OAuth2 has no granular scopes — the token inherits the full access of the\n> authorizing user.\n\n## Tool Catalog\n\nLegend: ⚠️ = write (blocked by `MM_READ_ONLY=true`) · 💥 = destructive (requires\n`MM_ALLOW_DESTRUCTIVE=true` **and** `confirm: true` per call)\n\n### Messaging (13)\n\n| Tool                 | Description                                                                         |\n| -------------------- | ----------------------------------------------------------------------------------- |\n| `post_message` ⚠️    | Post a message to a channel (optional `root_id`, `file_ids`, `props`).              |\n| `reply_thread` ⚠️    | Reply within a thread (`root_id`).                                                  |\n| `get_channel_posts`  | Paginated channel history (`page`/`per_page`, or `since`/`before`/`after` cursors). |\n| `get_thread`         | A root post and all its replies.                                                    |\n| `get_post`           | A single post by id.                                                                |\n| `search_posts`       | Full-text search within a team (`terms`, `is_or_search`).                           |\n| `edit_post` ⚠️       | Update a post's message (patch — message field only).                               |\n| `delete_post` 💥     | Delete a post.                                                                      |\n| `send_dm` ⚠️         | Open/get a DM (2 users) or group DM (3–8 users) and post a message.                 |\n| `pin_post` ⚠️        | Pin a post.                                                                         |\n| `unpin_post` ⚠️      | Unpin a post.                                                                       |\n| `add_reaction` ⚠️    | Add an emoji reaction (as the authenticated user).                                  |\n| `remove_reaction` ⚠️ | Remove an emoji reaction.                                                           |\n\n### Channels & Teams (12)\n\n| Tool                   | Description                                     |\n| ---------------------- | ----------------------------------------------- |\n| `list_teams`           | Teams the authenticated user belongs to.        |\n| `list_channels`        | The user's channels in a team.                  |\n| `get_channel`          | Channel metadata.                               |\n| `create_channel` ⚠️    | Create a public (`O`) or private (`P`) channel. |\n| `join_channel` ⚠️      | Join a channel (self).                          |\n| `leave_channel` ⚠️     | Leave a channel (self).                         |\n| `archive_channel` 💥   | Archive (soft-delete) a channel.                |\n| `list_channel_members` | Members of a channel (paginated).               |\n| `add_member` ⚠️        | Add another user to a channel.                  |\n| `remove_member` 💥     | Remove another user from a channel.             |\n| `get_unreads`          | Per-channel unread/mention counts for a team.   |\n| `mark_channel_read` ⚠️ | Mark a channel as viewed.                       |\n\n### Users & Presence (6)\n\n| Tool                   | Description                                          |\n| ---------------------- | ---------------------------------------------------- |\n| `get_me`               | The authenticated user.                              |\n| `get_user`             | A user by id or username (exactly one required).     |\n| `search_users`         | Search users by term.                                |\n| `get_user_status`      | A user's status (`online`/`away`/`dnd`/`offline`).   |\n| `set_status` ⚠️        | Set own status (`online \\| away \\| offline \\| dnd`). |\n| `set_custom_status` ⚠️ | Set own custom status (emoji + text).                |\n\n### Files (3)\n\n| Tool                | Description                                                                                          |\n| ------------------- | ---------------------------------------------------------------------------------------------------- |\n| `upload_file` ⚠️    | Upload a file to a channel (base64 content); returns file ids to attach via `post_message.file_ids`. |\n| `get_file`          | Download a file's content as base64 (configurable `max_bytes` cap, default 8 MiB).                   |\n| `get_file_metadata` | File info (`GET /files/{id}/info`).                                                                  |\n\n## Guardrails\n\n### Guardrail Variables\n\n| Variable                    | Effect                                                                                |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `MM_READ_ONLY=true`         | Every ⚠️ and 💥 tool hard-refuses at call time. Tools remain visible in `tools/list`. |\n| `MM_ALLOW_DESTRUCTIVE=true` | Required to unlock the 💥 tools.                                                      |\n| `MM_TEAM_ALLOWLIST`         | CSV of permitted team ids; calls targeting other teams are refused.                   |\n| `MM_CHANNEL_ALLOWLIST`      | CSV of permitted channel ids; calls targeting other channels are refused.             |\n| `MM_MAX_MESSAGE_LEN`        | Messages exceeding this length (Unicode code points) are rejected before sending.     |\n\n### Rules\n\n- Destructive tools (`delete_post`, `archive_channel`, `remove_member`) require **both**\n  `MM_ALLOW_DESTRUCTIVE=true` in the environment **and** an explicit `confirm: true` argument in\n  the tool call.\n- `MM_READ_ONLY=true` takes precedence over `MM_ALLOW_DESTRUCTIVE`; all ⚠️/💥 tools refuse.\n- Allowlists are checked against the resolved team/channel id for the call, not a display name.\n- Mattermost API errors (status code + message) are surfaced verbatim — never swallowed.\n\n## Register in an MCP Client\n\nThe server speaks MCP over **stdio**. Point your MCP client at the binary. Two ready-to-edit config\nexamples are in the `examples/` directory.\n\n### After a global install + `login`\n\nIf you installed globally and ran `mattermost-mcp login`, the credentials are already on disk — the\nclient config needs no `env` block at all:\n\n```json\n{\n  \"mcpServers\": {\n    \"mattermost\": {\n      \"command\": \"mattermost-mcp\"\n    }\n  }\n}\n```\n\n### Generic (`examples/mcp.json`)\n\nSuitable for any MCP client that follows the standard `mcpServers` schema (Cursor, Continue, etc.).\nCopy to `.mcp.json` in your project root and adjust the path and credentials:\n\n```json\n{\n  \"mcpServers\": {\n    \"mattermost\": {\n      \"command\": \"node\",\n      \"args\": [\"/absolute/path/to/mattermost-mcp/dist/index.js\"],\n      \"env\": {\n        \"MM_URL\": \"https://mattermost.example.com\",\n        \"MM_AUTH_MODE\": \"pat\",\n        \"MM_TOKEN\": \"your-personal-access-token\"\n      }\n    }\n  }\n}\n```\n\n### Claude Desktop (`examples/claude_desktop_config.json`)\n\nMerge into `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS (or the\nequivalent path on Windows/Linux). **Always use absolute paths.** Restart Claude Desktop after\nsaving.\n\n```json\n{\n  \"mcpServers\": {\n    \"mattermost\": {\n      \"command\": \"node\",\n      \"args\": [\"/absolute/path/to/mattermost-mcp/dist/index.js\"],\n      \"env\": {\n        \"MM_URL\": \"https://mattermost.example.com\",\n        \"MM_AUTH_MODE\": \"pat\",\n        \"MM_TOKEN\": \"your-personal-access-token\"\n      }\n    }\n  }\n}\n```\n\n## Integration Testing\n\nA `docker-compose.yml` ships in the repository. It starts a disposable Mattermost preview\ninstance:\n\n```bash\ndocker compose up -d\n# Mattermost is now running at http://localhost:8065\n# Create an account + team, then generate a Personal Access Token.\n```\n\nLive integration tests are **skipped by default** (so `npm test` stays offline and green). Set\n`MM_INTEGRATION=1` to enable them:\n\n```bash\nMM_INTEGRATION=1 \\\n  MM_URL=http://localhost:8065 \\\n  MM_AUTH_MODE=pat \\\n  MM_TOKEN=your-token \\\n  MM_TEST_CHANNEL_ID=<channel-id> \\\n  npm test\n```\n\n`MM_TEST_CHANNEL_ID` is optional; it only enables the post → get → delete write round-trip tests.\n\n## Development\n\n### Scripts\n\n| Script           | Purpose                                                                     |\n| ---------------- | --------------------------------------------------------------------------- |\n| `npm run build`  | Compile TypeScript → `dist/`                                                |\n| `npm run dev`    | Run the server from source over stdio (tsx, no build needed)                |\n| `npm start`      | Run the built server (`node dist/index.js`)                                 |\n| `npm test`       | Run the vitest suite (integration tests skipped without `MM_INTEGRATION=1`) |\n| `npm run lint`   | ESLint + Prettier check                                                     |\n| `npm run format` | Prettier write (auto-fix formatting)                                        |\n\n## License\n\nMIT\n","readmeFilename":"README.md"}