matrix-mcpl
Provides tools for interacting with Matrix homeservers, including sending and replying to messages, managing rooms and subscriptions, handling threads, reacting, typing indicators, and fetching history.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@matrix-mcplsend a DM to @alice:example.org saying 'meeting moved to 3pm'"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
matrix-mcpl
Standalone Matrix MCPL server: connects a Matrix account (rooms, DMs) to an
MCPL host as a first-class channel surface. Sibling of
slack-mcpl and
discord-mcpl, built on
@animalabs/mcpl-core.
Works in plain MCP mode too (tools only, no push events or channels).
Why Matrix fits
Matrix pushes events to an ordinary HTTP client over the /sync long-poll.
There is no webhook to expose and no second socket protocol to negotiate, so
this server runs spawned over stdio with no inbound network path — the property
Slack needs Socket Mode for and Discord needs a gateway for. Matrix also has
real typing notifications, first-class threads, and redaction, so
channels/typing, threadId and MCPL rollback all map onto native operations.
Related MCP server: ircv3-mcp
Features
Channels: every joined room is registered as an MCPL channel (
matrix:<roomId>);channels/publishreplies into the room's active thread automatically.Real-time events via
/sync— no public webhook URL needed.Addressing model: mentions and DMs are always delivered; ambient room chatter flows only from subscribed rooms (auto-subscribe on first mention, opt out with
unsubscribe_room). Events carry MCPL RFC-001chat:*tags for host-side wake gating.Mentions: reads
m.mentions.user_ids(intentional mentions, Matrix 1.7), falling back tomatrix.topills and then to the display name for older clients. An@roombroadcast is deliberately not a personal mention — it tagsmatrix:room-pingand stays ambient.Threads: incoming
m.threadreplies carrythreadId;reply_messageposts into a thread by default, withthread: falsefor a rich reply.Markdown both ways: outgoing markdown is rendered into Matrix's
org.matrix.custom.htmlsubset (sanitized against an allowlist) with the plain text kept asbody; incomingformatted_bodyis flattened back to text, with pills rendered as@Name (mxid:@user:server)so the agent can paste an ID straight into a tool call.Attachments: incoming media is forwarded as
mxc://refs and fetched on demand viafetch_attachment, which resolves against the configured homeserver only and is size-capped at 5MB with a streaming budget.Typing:
channels/typingdrives real Matrix typing notifications, so humans see the agent thinking.Rollback:
matrix.messagingsupports MCPL checkpoints — rolling back redacts the events the bot sent after the checkpoint. Redacting your own events is always permitted, so this is reliable rather than best-effort (a redaction tombstone does remain visible).Resumption: with
MATRIX_STORAGE_FILEset, the sync position persists, so messages sent while the server is down arrive on restart rather than being lost. On a genuine cold start the replayed timeline is dropped instead of flooding the agent with history.
Tools
send_message, reply_message, send_dm, add_reaction, edit_message,
delete_message, list_rooms, refresh_rooms, join_room, leave_room,
fetch_history, fetch_thread, find_user, fetch_attachment,
subscribe_room, unsubscribe_room, list_subscriptions.
Feature sets: matrix.messaging (rollback-capable), matrix.history,
matrix.rooms.
No end-to-end encryption
This server has no crypto. Rooms with m.room.encryption state are flagged
encrypted: true in their descriptor and in list_rooms, and a warning is
logged at startup — their messages arrive as undecryptable m.room.encrypted
events and are not forwarded.
Use unencrypted rooms for the agent. On your own homeserver this is a per-room decision at creation time; note that Element defaults DMs and private rooms to encrypted, so create the agent's rooms with encryption explicitly off.
Adding E2EE later means a persistent crypto store (matrix-bot-sdk's
RustSdkCryptoStorageProvider), device identity that must not be lost, and
history from before the bot joined staying unreadable — megolm keys are only
shared with devices present when a message was sent, so a device that joins
later never gets them. It is a bolt-on to the adapter, not a rewrite.
History from before the bot joined
Unencrypted, this is a separate question from encryption and usually goes the
way you want. What the bot can read is set by the room's
m.room.history_visibility state:
Value | The bot can read… |
| everything, without even joining |
| all history, including from before it joined (assumed when the event is absent) |
| from the moment it was invited |
| only from the moment it joined |
So in a typical room the agent joins and can immediately page back through the
whole timeline via fetch_history, and its first-interaction backscroll covers
conversation that predates it.
If the agent seems oddly amnesiac about anything before it arrived, check this setting before suspecting the server — in Element it is Room Settings → Security & Privacy → "Who can read history?".
Setup
1. Create the bot account
Any normal Matrix account works — no app registration, no OAuth scopes. On your own homeserver:
register_new_matrix_user -u connectome-agent -c /etc/matrix-synapse/homeserver.yamlOr register through any client. Then set a display name, since it is what humans will address the agent by.
2. Get an access token
curl -XPOST -d '{
"type": "m.login.password",
"identifier": { "type": "m.id.user", "user": "connectome-agent" },
"password": "…",
"initial_device_display_name": "matrix-mcpl"
}' 'https://matrix.example.org/_matrix/client/v3/login'Take access_token from the response. It does not expire unless the device is
logged out, so keep it out of the recipe and pass it through the environment.
3. Invite the bot
Invite it to the rooms it should watch — it auto-accepts invites by default
(restrict this with MATRIX_INVITE_ALLOWLIST, or turn it off with
MATRIX_AUTOJOIN=false and use the join_room tool instead). DMs work without
any invite handling: anyone can open one, and MATRIX_DM_USERS whitelists who
gets through.
4. Run
npm install
npm run build
MATRIX_HOMESERVER_URL=https://matrix.example.org \
MATRIX_ACCESS_TOKEN=syt_… \
MATRIX_STORAGE_FILE=./matrix-mcpl-storage.json \
matrix-mcpl --stdio
# or: matrix-mcpl --tcp 9041Environment
Variable | Required | Description |
| yes | Base URL of the homeserver ( |
| yes | Access token for the bot account |
| no | Comma-separated MXID whitelist for DMs; others' DMs are dropped |
| no |
|
| no | Comma-separated MXIDs whose invites are accepted; all others declined |
| no | JSON file persisting the |
| no | JSON file persisting ambient subscriptions across restarts |
| no | Messages fetched on first interaction with a room (default 50) |
| no |
|
| no | Comma-separated MXIDs of sibling agents; their messages are tagged |
| no | Absolute path for a diagnostic file log |
Running multiple agents
One process per agent, but only one installation — build once and point several
spawn configs at the same dist/src/index.js with different environments. The
adapter binds a single identity at connect time (one whoami, and self-filtering
and mention detection key off it), so there is no multi-account mode.
These must differ per agent. Sharing any of them silently breaks things:
Variable | Why it cannot be shared |
| One Matrix account per agent. Sharing one makes each agent's self-filter suppress the others' messages |
| Holds the sync token and filter ID for one account; two writers clobber each other's sync position |
| Per-agent ambient room subscriptions |
| Only when using the TCP transport; stdio has no conflict |
Budget roughly one idle /sync long-poll and 50–80MB of Node per agent.
Separate accounts also help with rate limits, which Synapse buckets per user.
Agents sharing a room
Sibling agents hear each other by default: the adapter filters only the agent's
own messages, and send_message sends m.text like any human client. Each
incoming message is rendered Name: text with the author in metadata and in
the channels/incoming author field, so an agent can see who spoke and decide
for itself whether to answer.
Two things to set up for this:
Subscribe the shared room. Ambient (non-mention) messages only flow from subscribed rooms. Mention the agent once in the room and it auto-subscribes permanently, or call
subscribe_room, or pre-seedMATRIX_SUBSCRIPTIONS_FILEwith the room ID. Note this is not the recipe'schannelSubscription, which is a host-side concern — both matter, for different reasons.List the siblings in
MATRIX_PEER_AGENTSon each agent. Their messages are then taggedchat:from-agentrather thanchat:from-human, which is what lets a wake policy treat "another agent said something" differently from "a person said something". Without it every sender looks human to the gate.
On loops. Judgement about when to stop is the primary control, and it is usually enough — but two agents being polite at each other is a well-known way to burn tokens overnight, and it does not need either one to be malfunctioning. Two backstops sit under it:
chat:ambientis throttled to one wake per 2 minutes andchat:from-agentto one per minute in this server's declareddefaultTreatment; the host applies these unless agate.jsonpolicy overrides them.If a specific pair does start ping-ponging, the cheapest fix is to have their inter-agent traffic use
send_messagewithnotice: truewhile leavingMATRIX_ACCEPT_NOTICESunset — they then cannot hear each other at all, while humans still see everything.
Worth watching the first few multi-agent sessions with MATRIX_MCPL_DEBUG_LOG
set before leaving them running unattended.
Connectome recipe
Add to your recipe's mcpServers block (see recipe-snippet.json):
"matrix": {
"command": "node",
"args": ["/absolute/path/to/matrix-mcpl/dist/src/index.js", "--stdio"],
"env": {
"MATRIX_HOMESERVER_URL": "https://matrix.example.org",
"MATRIX_ACCESS_TOKEN": "${MATRIX_ACCESS_TOKEN}",
"MATRIX_STORAGE_FILE": "./matrix-mcpl-storage.json",
"MATRIX_SUBSCRIPTIONS_FILE": "./matrix-subscriptions.json"
},
"channelSubscription": ["matrix:!yourroom:example.org"]
}Subscribing at the MCPL layer is only half of it — the host's wake policy
decides whether an arriving event triggers inference. Add a matching rule to
_config/gate.json:
{
"name": "matrix-main",
"match": { "scope": ["mcpl:channel-incoming"], "channel": "matrix:!yourroom:example.org" },
"behavior": "always"
}Development
npm run typecheck
npm testThe content.ts helpers are pure functions and carry the test suite; the
adapter and server layers are exercised against a live homeserver. To drive the
server by hand without running a full agent, point
mcpl-harness at
matrix-mcpl --tcp 9041.
Provenance
Structure follows slack-mcpl closely — the MCPL plumbing (channel
registration, feature-set gating, push/incoming routing, subscription
persistence, backscroll-on-first-interaction) is that server's design with
Matrix domain logic swapped in. Divergences are noted in comments where the
platforms genuinely differ.
Note: slack-mcpl logs two lines with console.log (client-initialized and
client-disconnected), which writes to the protocol channel in stdio mode. Those
are console.error here.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseBqualityCmaintenanceThe most powerful MCP server for Slack Workspaces. This integration supports both Stdio and SSE transports, proxy settings and does not require any permissions or bots being created or approved by Workspace admins 😏.21,766MIT
- AlicenseAqualityAmaintenanceAn IRCv3 MCP server that enables agents to act as a mini IRC client: read channels as transcripts, send messages, reply to threads, add reactions, fetch history, and manage channel membership via MCP tools.17111MIT
- Flicense-qualityBmaintenanceA Model Context Protocol server for Matrix that gives AI assistants read/write access to Matrix rooms, semantic search over message history, and real-time message notifications.
- Alicense-qualityCmaintenanceMCP server for Matrix that lets Claude list rooms, search/read messages, send messages and files, react, create rooms, and invite users, with multi-homeserver support and safe-by-default writes; no end-to-end encryption.MIT
Related MCP Connectors
Hosted AgentLux MCP server for marketplace, identity, creator, services, and social flows.
Remote MCP server for The Colony — a social network for AI agents (posts, DMs, search, marketplace).
Markdown-first MCP server for Notion API with 8 composite tools and 39 actions.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/almostmachines/matrix_mcpl'
If you have feedback or need assistance with the MCP directory API, please join our Discord server