Matrix <=> Mastodon bot
Clone or download
Latest commit 1576e8e Sep 20, 2018

MXToot - Matrix-Mastodon bot written on java.




  • openjdk 8 (openjdk 9, 10 don't supported, I need time to test it).

Run application service


java -jar mxtoot-X.X.X.jar check mxtoot.yaml

will check you configuration in the mxtoot.yaml file.


java -Xmx100m -jar mxtoot-X.X.X.jar server mxtoot.yaml

will run the application service.

An example mxtoot.service file is provided for systemd usage with mxtoot home user.

Invite a bot

Invite a bot with unique mxid like '@mxtoot_clientapp:homeserver.url' where

  • homeserver.url is a homeserver which attached to the applicatin service.
  • clientapp is a name of the mastodon application.

It is important that the name of the bot be unique. You can do this by choose unique clientapp (for example, your mastodon's username).

Application service will create the bot and join it to the invited room. Also user who sent invite will be a owner of the bot.

Registration bot in the Mastodon.

To start registration flow use command !reg <mastodon.url> where first parameter is a mastodon url. Bot will answer with a url to authorize in the mastodon. Please open this url, login into your account and authorize new application. After this copy the authorization code and execute command !auth <authorization.code>

After this you can enable your home stream by command !timeline auto, post new messages !toot Hello, World!, reply to messages !reply <status_id> text, boost messages !boost <status_id>, setup format of the messages, ...

Also owner can rejoin bot to a new room by command !join <room_id>.

To delete bot execute command !leave. If bot detects that it doesn't exist in any rooms it will send deactivate request to the homeserver and delete itself in the application service.


Each application service should me registered on the homeserver via registration file. There is an example how to register mxtoot:

# unique identifier of the application service
id: "mxtoot"

# url of the application service
url: ""

# token AS will add to requests to HS
as_token: "EapiSh7h"

# token token HS will add to requests to AS
hs_token: "tah6Zoox"

# This is a field which denotes the user_id localpart when using the AS token
sender_localpart: "mxtoot"

  users: # List of users we're interested in
    - exclusive: true
      regex: "@mxtoot_.*"
  rooms: [] # List of aliases we're interested in
  aliases: [] # List of room ids we're interested in


Application service can use certificates stored in pkcs12 file (at current moment) to work under secure connection (https).

To convert pem-based certificates to pkcs12 you can use next command:

openssl pkcs12 -export -inkey privkey.pem -in fullchain.pem -out mxtoot.pkcs12

where privkey.pem and fullchain.pem are private key and certificate with public key and all parent certificates. You can use certificates from Lets Encrypt.


There is only an one configuration yaml-file which include all settings.


Url of the matrix homeserver. For example ""


Initial bot's displayName. If command is enabled it is possible to change this name. Can be invoked only by owner. For example, "mxtoot".


Initial command's prefix. If command is enabled it is possible to change prefix. Can be invoked only by owner. For example, "!".

DO NOT USE "/". This character is internal used by Web Riot and all commands with "/" prefix will be invoked only by Riot not bot. Workaround ro execute commands: place one or more spaces before prefix.

Also there is a special placeholder {{display_name}} which will be replaced by current bot's name. You can set prefix as "{{display_name}}:" and all commands should be execute by bot's mention. For example, "mxtoot: help".


There is a list of all enabled commands described by command's class. See more.


There are two run states: APPLICATION_SERVICE and STANDALONE.

In STANDALONE mode each of the bots will run in separated thread and receive events from /sync request like a common client.

In APPLICATION_SERVICE mode bots wont'be run in threads and will receive events only from application service via /transaction endpoint. This state is recommended because reduces load of the homeserver.


May be true or false.

When Application service receive events via /transaction endpoint it will validate event.

When strictMode is enabled if unknown field is found application service will throw exception and stop it process.

When strictMode is disabled it will skip event's validations and all unknown fields will be ignored.







Initial template of the post, reply, boost, mention, favourite and follow messages which come from Mastodon. To create messages uses jmustache library, it is another java implementation of the logic-less templating engine mustache.

For example, how you can define template:

postFormat: >
    <hr/>[{{id}}]: <a href="{{url}}">{{url}}</a>:<br/>
    {{account.acct}} at {{created_at}} wrote:<br/>

When bot receive message from the Mastodon it fill all placeholders {{value}} by values and write the message to the room. So, portFormat describe how display general toots from the Mastodon, replyFormat - replies, boostFormat - boost/reblog messages.

Available placeholders:


Attribute Description Nullable
id The notification ID no
type One of: "mention", "reblog", "favourite", "follow" no
created_at The time the notification was created no
account The Account sending the notification to the user no
status The Status associated with the notification, if applicable yes


Attribute Description Nullable
id The ID of the status no
uri A Fediverse-unique resource ID no
url URL to the status page (can be remote) yes
account The Account which posted the status no
in_reply_to_id null or the ID of the status it replies to yes
in_reply_to_account_id null or the ID of the account it replies to yes
reblog null or the reblogged Status yes
content Body of the status; this will contain HTML (remote HTML already sanitized) no
created_at The time the status was created no
emojis An array of Emoji no
reblogged Whether the authenticated user has reblogged the status yes
favourited Whether the authenticated user has favourited the status yes
sensitive Whether media attachments should be hidden by default no
spoiler_text If not empty, warning text that should be displayed before the actual content no
visibility One of: public, unlisted, private, direct no
media_attachments An array of Attachments no
mentions An array of Mentions no
tags An array of Tags no
application Application from which the status was posted yes

If fetch statuses is enabled then add next fields:

Attribute Description Nullable
in_reply_to full origin Status in replies messages yes
in_replay_to_account full origin Account in replies messages yes


Attribute Description Nullable
id The ID of the account no
username The username of the account no
acct Equals username for local users, includes @domain for remote ones no
display_name The account's display name no
locked Boolean for when the account cannot be followed without waiting for approval first no
created_at The time the account was created no
followers_count The number of followers for the account no
following_acount The number of accounts the given account is following no
statuses_count The number of statuses the account has made no
note Biography of user no
url URL of the user's profile page (can be remote) no
avatar URL to the avatar image no
header URL to the header image no


Attribute Description Nullable
shortcode The shortcode of the emoji no
static_url URL to the emoji static image no
url URL to the emoji image no


Attribute Description Nullable
id ID of the attachment no
type One of: "image", "video", "gifv", "unknown" no
url URL of the locally hosted version of the image no
remote_url For remote images, the remote URL of the original image yes
preview_url URL of the preview image no
text_url Shorter URL for the image, for insertion into text (only present on local images) yes


Attribute Description Nullable
url URL of user's profile (can be remote) no
username The username of the account no
acct Equals username for local users, includes @domain for remote ones no
id Account ID no


Attribute Description Nullable
name The hashtag, not including the preceding # no
url The URL of the hashtag no


Attribute Description Nullable
name Name of the app no
website Homepage URL of the app yes


Defines how display date and time from all Mastodon's messages. See more on the in the Section "Patterns for Formatting and Parsing".


Defines locale of the localized date terms in the dateTimeFormat template.

For example, you can set dateTimeFormat: "MMM, dd, yyyy" and dateTimeLocale: "ru". Then date will be rendered as Май, 02, 2018 because the Russian locale was defined.


May be true or false.

Also there are a lot of dropwizard's settings. You can check it in the corresponding page.

Because synapse doesn't work with zipped requests it need to disable zipping. And increase timeouts to avoid a lot of timeout errors in the /sync request (in STANDALONE run mode).

  gzipEnabled: false
  gzipEnabledForRequests: false
  chunkedEncodingEnabled: false
  timeout: 20s


There are two command's categories: commands which can be invoked only by owner (who invited bot) and commands which can be invoked as access policy configured (everyone or only owner).

Access policy is configured by command SetAccessPolicy To use commands you should list all available commands (class names) in the command setting in the configuration file.

Leave current room. If bot isn't available in any rooms it will delete itself.

Set new name.

Just pong.

Set or show access policy. All commands are divided into two categories: commands which can be invoked only by owner (who invited bot) or category which is set by this command.

Possible values: OWNER or ALL.

Rejoin to a new room. Bot will leave from old room.

Set or show command prefix, override the prefix setting.

Set default command. If invoked unknown commands or entered some text it would invoke the default command.

For example, if invoke !default toot every message will be tooted into the Mastodon.

Show all commands.


Start registration flow.

Syntax: !reg mastodon.server.tld where mastodon.server.tld is you mastodon server (,, etc.)


Validate auth code.


Start or stop timeline. Bot create connection to the streaming resource and will receive all new messages.

Possible value: on, off, auto (autorestart after application service's restart).


Post a new public message to the Mastodon.


Post a new private message to the Mastodon.


Post a new unlistedpublic message to the Mastodon.


Post a new direct message to the Mastodon.


Reply to the message from Mastodon. The reply has the same visibility (public, private, unlisted, direct) as the origin.


Some messages from Mastodon has only identifier of the statuses or accounts. If this parameter is true then bot will retrieve this statuses or accounts by id.


Set or show post, reply or boost message templates.


Boost(reblog) message.


Follow to somebody.




Mute somebody.




Block somebody.




Show followers of the specified user id.


Show followings of the specified user id.


To build you need jdk 8 (oracle or openjdk) and apache maven 3.5.2 or higher.

  1. clone repository git clone
  2. cd mxtoot
  3. build common modules and mxtoot mvn clean package

Don't hesitate to contact me in the room. :-)