| Internet-Draft | RFC MyTeams (MTP) | April 2026 |
| Zarrillo, et al. | Expires 17 October 2026 | [Page] |
This document describes the MyTeams Protocol (MTP), a text-based application protocol used by the MyTeams server and CLI client. MTP operates over TCP and defines the commands required by the MyTeams subject: user login, direct messages, team subscription, hierarchical resources, persistence, and asynchronous events.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 17 October 2026.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
The MyTeams Protocol (MTP) is a client-server protocol designed for a collaborative communication application inspired by team, channel, thread, reply, and direct-message workflows.¶
The protocol is session-oriented. Each client opens a TCP connection to the server, authenticates with a user name, and then send commands to the server.¶
The following terms are used throughout this document:¶
User: an identity persisted by the server and referenced by a UUID.¶
Team: a top-level collaborative space containing subscribed users and channels.¶
Channel: a container inside a team used to organize threads.¶
Thread: an initial post inside a channel, followed by replies.¶
Reply: a comment attached to a thread. The subject uses both "comment" and "reply" for the same resource.¶
Direct Message: a private message exchanged between exactly two users.¶
MTP follows a client-server architecture over TCP. Each client session is independent and maintains its own authentication state.¶
The server has two session states: unauthenticated and
authenticated. In the unauthenticated state, only
LOGIN is valid. All other commands MUST be rejected as
unauthorized.¶
Once authenticated, the client MAY query users, exchange direct messages, subscribe to team. The server MUST validate both the command syntax and the caller permissions before applying any modification.¶
The server MUST persist users, team hierarchy, subscriptions, replies, and direct-message history when it shuts down. When a save file exists at startup, the server MUST restore the saved state before accepting client traffic. See the section "Persistent Data".¶
Team-related asynchronous events MUST only be delivered to authenticated sessions subscribed to the corresponding team. Direct-message events MUST only be delivered to the addressed recipient.¶
All protocol messages are transmitted as UTF-8 text. A request is a single line composed of an uppercase command token followed by zero or more arguments.¶
COMMAND ["ARG1"] ["ARG2"] ... ["ARGN"]\n
Commands are case-sensitive. Any command argument MUST be enclosed in double quotes. A missing opening or closing quote MUST be treated as a malformed request.¶
UUID arguments MUST be transmitted in their canonical textual representation. Unless stated otherwise, names are limited to 32 bytes, descriptions to 255 bytes, and message bodies to 512 bytes.¶
C: LOGIN "user_name" S: 200 OK "uuid"
Authenticates the current TCP session with the provided user
name. The user_name argument MUST be a quoted UTF-8
string of 1 to 32 bytes.¶
If the user name does not exist in persistent storage, the server MUST create a new user and assign a UUID. If it already exists, the server MUST reuse the existing user record.¶
200 OK "uuid": Authentication succeeded.¶
400 BAD_REQUEST: Malformed request (e.g.,
unexpected arguments).¶
400 INVALID_USERNAME: The username format is
invalid.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: LOGOUT S: 200 OK
Terminates the authenticated state of the current session. The underlying TCP connection MAY then be closed by either peer.¶
Logging out MUST NOT delete the user or any persisted resource.¶
200 OK: Logout succeeded.¶
400 BAD_REQUEST: Malformed request (e.g.,
unexpected arguments).¶
401 UNAUTHORIZED: The session is not authenticated.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: USERS S: 200 "user_uuid" "user_name" "status" [| "user_uuid" "user_name" "status" ...]
Returns the list of all users known by the domain together with their connection status. This command requires an authenticated session.¶
200 "user_uuid" "user_name" "status"
[ | ... ]: The user list is returned. The response MAY
contain no entry when the domain has no known user.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: USER "user_uuid" S: 200 "user_uuid" "user_name" "status"
Returns the details of a single user identified by
"user_uuid". The caller MUST be authenticated.¶
200 "user_uuid" "user_name"
"status": The user details are returned.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated.¶
404 UNKNOWN_USER "user_uuid": The referenced user UUID does not
exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: SEND "user_uuid" "message_body" S: 200 OK
Sends a direct message from the authenticated user to the user
identified by "user_uuid". The message body MUST be a
quoted string no longer than 512 bytes.¶
On success, the server MUST persist the message with its sender, recipient, and creation timestamp. If the recipient is online, the server SHOULD emit the corresponding event to that user.¶
200 OK: The message was accepted and persisted.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated.¶
404 UNKNOWN_USER "user_uuid": The referenced recipient UUID
does not exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: MESSAGES "user_uuid" S: 200 "sender_uuid" "message_timestamp" "message_body" [| "sender_uuid" "message_timestamp" "message_body" ...]
Returns the private-message history between the authenticated
caller and the user identified by "user_uuid".¶
The server SHOULD return messages in chronological order from oldest to newest.¶
200 "sender_uuid" "message_timestamp" "message_body" [| ...]: The message history is returned.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated.¶
404 UNKNOWN_USER "user_uuid": The referenced user UUID does not
exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: SUBSCRIBE "team_uuid" "user_uuid" S: 200 OK
Subscribes the user identified by "user_uuid" to the
team identified by "team_uuid". Once subscribed, that
user becomes
authorized to receive team-related events and to access team,
channel, thread, and reply operations within that team.¶
If the referenced user is already subscribed, the server MAY treat the command as a successful no-op.¶
200 OK: The subscription is active (or already
active).¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated.¶
404 UNKNOWN_TEAM "team_uuid": The referenced team UUID does not
exist.¶
404 UNKNOWN_USER "user_uuid": The referenced user UUID does not
exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: UNSUBSCRIBE "team_uuid" "user_uuid" S: 200 OK
Removes the user identified by "user_uuid" from the
subscriber set of the specified team.¶
200 OK: The user is unsubscribed (or was not
subscribed).¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated.¶
404 UNKNOWN_TEAM "team_uuid": The referenced team UUID does not
exist.¶
404 UNKNOWN_USER "user_uuid": The referenced user UUID does not
exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: SUBSCRIBED "user_uuid" S: 200 "team_uuid"[|"team_uuid"...]
Returns the UUID list of teams to which the user identified by
"user_uuid" is subscribed, separated by pipe
characters.¶
200 "team_uuid"[|"team_uuid"...]: The subscription list is returned.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated.¶
404 UNKNOWN_USER "user_uuid": The referenced user UUID does not exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: SUBSCRIBEDTEAM "team_uuid" S: 200 "user_uuid" "user_name" "status" [| "user_uuid" "user_name" "status" ...]
Returns the list of users subscribed to the team identified by
"team_uuid", separated by pipe characters. Each entry
contains the user UUID, user name and connection status, in the
same format as the USERS command.¶
200 "user_uuid" "user_name" "status"[|...]: The subscriber list is returned.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated.¶
404 UNKNOWN_TEAM "team_uuid": The referenced team UUID does not exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: CREATETEAM "team_name" "team_description" S: 200 OK "team_uuid"
Creates a new team with its name of a maximum of 32 bytes length and description of a maximum of 255 bytes.¶
Team names MUST be unique within the domain. The creator MUST become subscribed to the newly created team.¶
200 OK "team_uuid": Team created.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated.¶
409 ALREADY_EXISTS: A team with the same name
already exists.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: CREATECHANNEL "team_uuid" "channel_name" "channel_description" S: 200 OK "channel_uuid"
Creates a channel inside the team identified by
"team_uuid". The channel name has a maximum length of
32 bytes and the description a maximum length of 255 bytes.¶
The caller MUST be subscribed to the target team. Channel names MUST be unique within a given team.¶
200 OK "channel_uuid": Channel created.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated,
or the caller is not subscribed to the team.¶
404 UNKNOWN_TEAM "team_uuid": The referenced team UUID does not
exist.¶
409 ALREADY_EXISTS: A channel with the same name
already exists in the team.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: CREATETHREAD "team_uuid" "channel_uuid" "thread_title" "thread_message" S: 200 OK "thread_uuid"
Creates a thread inside the specified channel. The title of the thread is at maximum 32 bytes.¶
The caller MUST be subscribed to the team owning the channel. The thread title MUST be unique within that channel. The server MUST store both the thread metadata and its initial message.¶
200 OK "thread_uuid": Thread created.¶
400 BAD_REQUEST: Malformed request (e.g., invalid
hierarchy).¶
401 UNAUTHORIZED: The session is not authenticated,
or the caller is not subscribed to the team.¶
404 UNKNOWN_TEAM "team_uuid": The referenced team UUID does not
exist.¶
404 UNKNOWN_CHANNEL "channel_uuid": The referenced channel UUID
does not exist in the current hierarchy.¶
409 ALREADY_EXISTS: A thread with the same title
already exists in the channel.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: CREATECOMMENT "team_uuid" "channel_uuid" "thread_uuid" "comment_body" S: 200 OK "reply_uuid"
Creates a reply in the specified thread. The body needs to be less than 512 bytes in order to proceed.¶
The caller MUST be subscribed to the target team. The server MUST verify that the thread belongs to the supplied channel and team before storing the reply.¶
200 OK "reply_uuid": Reply created.¶
400 BAD_REQUEST: Malformed request (e.g., invalid
hierarchy).¶
401 UNAUTHORIZED: The session is not authenticated,
or the caller is not subscribed to the team.¶
404 UNKNOWN_TEAM "team_uuid": The referenced team UUID does not
exist.¶
404 UNKNOWN_CHANNEL "channel_uuid": The referenced channel UUID
does not exist in the current hierarchy.¶
404 UNKNOWN_THREAD "thread_uuid": The referenced thread UUID does
not exist in the current hierarchy.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: LISTTEAM S: 200 "team_uuid"[|"team_uuid"...]
Lists all teams in the domain.¶
200 "team_uuid"[|"team_uuid"...]: The team collection is returned.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: LISTCHANNEL "team_uuid" S: 200 "channel_uuid"[|"channel_uuid"...]
Lists all channels with the team provided.¶
The caller MUST be subscribed to the referenced team.¶
200 "channel_uuid"[|"channel_uuid"...]: The channel collection is returned.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated,
or the caller lacks the required team subscription.¶
404 UNKNOWN_TEAM "team_uuid": The referenced team UUID does not
exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: LISTTHREAD "channel_uuid" S: 200 "thread_uuid"[|"thread_uuid"...]
Lists all threads with the channel provided.¶
The caller MUST be subscribed to the team that owns the referenced channel.¶
200 "thread_uuid"[|"thread_uuid"...]: The thread collection is returned.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated,
or the caller lacks the required team subscription.¶
404 UNKNOWN_TEAM "team_uuid": The team owning the referenced
channel does not exist.¶
404 UNKNOWN_CHANNEL "channel_uuid": The referenced channel UUID
does not exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: LISTREPLY "thread_uuid" S: 200 "reply_uuid"[|"reply_uuid"...]
Lists all replies with the thread provided.¶
The caller MUST be subscribed to the team that owns the referenced thread.¶
200 "reply_uuid"[|"reply_uuid"...]: The reply collection is returned.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated,
or the caller lacks the required team subscription.¶
404 UNKNOWN_TEAM "team_uuid": The team owning the referenced
thread does not exist.¶
404 UNKNOWN_CHANNEL "channel_uuid": The channel owning the
referenced thread does not exist.¶
404 UNKNOWN_THREAD "thread_uuid": The referenced thread UUID does
not exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: INFOUSER "user_uuid" S: 200 "user_uuid" "user_name" "status"
Returns the details of the user identified by
"user_uuid".¶
200 "user_uuid" "user_name" "status":
The user details are returned.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated.¶
404 UNKNOWN_USER "user_uuid": The given user does not exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: INFOTEAM "team_uuid" S: 200 "team_uuid" "team_name" "team_description"
Returns the selected team details provided in the parameter.¶
The caller MUST be subscribed to the referenced team.¶
200 "team_uuid" "team_name"
"team_description": The team details are returned.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated,
or the caller lacks the required team subscription.¶
404 UNKNOWN_TEAM "team_uuid": The referenced team UUID does not
exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: INFOCHANNEL "channel_uuid" S: 200 "channel_uuid" "channel_name" "channel_description"
Returns the information about the channel provided.¶
The caller MUST be subscribed to the team that owns the referenced channel.¶
200 "channel_uuid" "channel_name"
"channel_description": The channel details are
returned.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated,
or the caller lacks the required team subscription.¶
404 UNKNOWN_TEAM "team_uuid": The team owning the referenced
channel does not exist.¶
404 UNKNOWN_CHANNEL "channel_uuid": The referenced channel UUID
does not exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: INFOTHREAD "thread_uuid" S: 200 "thread_uuid" "author_uuid" "thread_timestamp" "thread_title" "thread_message"
Returns the information about the thread provided.¶
The caller MUST be subscribed to the team that owns the referenced thread.¶
200 "thread_uuid" "author_uuid"
"thread_timestamp" "thread_title"
"thread_message": The thread details are returned.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated,
or the caller lacks the required team subscription.¶
404 UNKNOWN_TEAM "team_uuid": The team owning the referenced
thread does not exist.¶
404 UNKNOWN_CHANNEL "channel_uuid": The channel owning the
referenced thread does not exist.¶
404 UNKNOWN_THREAD "thread_uuid": The referenced thread UUID does
not exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
C: INFOREPLY "reply_uuid" S: 200 "reply_uuid" "author_uuid" "reply_timestamp" "reply_body"
Returns the information about the reply provided.¶
The caller MUST be subscribed to the team that owns the referenced reply.¶
200 "reply_uuid" "author_uuid" "reply_timestamp"
"reply_body": The reply details are returned.¶
400 BAD_REQUEST: Malformed request.¶
401 UNAUTHORIZED: The session is not authenticated,
or the caller lacks the required team subscription.¶
404 UNKNOWN_REPLY "reply_uuid": The referenced reply UUID does
not exist.¶
500 INTERNAL_ERROR: Unexpected server error.¶
The server MUST persist all relevant data to ensure durability across sessions.¶
MTP uses a custom binary storage format composed of structured records.¶
The hierarchy can be setup in many different ways. It is up to the implementation of this protocol. The native hierarchy will be:¶
saved/
├── users/
│ ├── <user_uuid>.dat
│ └── ...
├── teams/
│ ├── <team_uuid>.dat
│ └── ...
├── channels/
│ ├── <channel_uuid>.dat
│ └── ...
├── threads/
│ ├── <thread_uuid>.dat
│ └── ...
└── dmessages/
├── <dmessage_uuid>.dat
└── ...
Each file MUST begin with a fixed-size header followed by a sequence of records.¶
All multi-byte integer fields in persistent files MUST be encoded in little-endian byte order.¶
The magic number bytes are 4D 54 50 00 (ASCII
MTP\0), which corresponds to the little-endian
32-bit value 0x0050544D.¶
+----------------------+
| Magic Number (4B) |
| Record Count (8B) |
+----------------------+
| Record 1 |
| Record 2 |
| ... |
+----------------------+
Each record MUST follow a TLV (Type-Length-Value) structure.¶
+----------------------+
| Type (2B) |
| Value Length (4B) |
| Value (variable) |
+----------------------+
The following record types are defined:¶
0x0001 (bytes 01 00): User¶
0x0002 (bytes 02 00): Team¶
0x0003 (bytes 03 00): Channel¶
0x0004 (bytes 04 00): Thread¶
0x0005 (bytes 05 00): Reply¶
0x0006 (bytes 06 00): Subscription¶
0x0007 (bytes 07 00): Direct Message¶
+----------------------+
| UUID (16B) |
| Name Length (2B) |
| Name (variable) |
+----------------------+
+------------------------+
| UUID (16B) |
| Name Length (2B) |
| Name (variable) |
| Description Length (2B)|
| Description (variable) |
| Created At (8B) |
+------------------------+
+------------------------+
| UUID (16B) |
| Team UUID (16B) |
| Name Length (2B) |
| Name (variable) |
| Description Length (2B)|
| Description (variable) |
| Created At (8B) |
+------------------------+
+----------------------+
| UUID (16B) |
| Channel UUID (16B) |
| Author UUID (16B) |
| Title Length (2B) |
| Title (variable) |
| Message Length (4B) |
| Message (variable) |
| Created At (8B) |
+----------------------+
+----------------------+
| UUID (16B) |
| Thread UUID (16B) |
| Author UUID (16B) |
| Content Length (4B) |
| Content (variable) |
| Timestamp (8B) |
+----------------------+
Subscriptions are stored in the corresponding
<team_uuid>.dat file. The first record is the team
record itself, and subsequent records contain all
subscriptions for that team.¶
+----------------------+
| User UUID (16B) |
| Team UUID (16B) |
+----------------------+
+----------------------+
| UUID (16B) |
| Sender UUID (16B) |
| Receiver UUID (16B) |
| Content Length (4B) |
| Content (variable) |
| Timestamp (8B) |
+----------------------+
The server MUST reject malformed or unauthorized requests without mutating persistent state.¶
400 BAD_REQUEST: invalid syntax, invalid argument
count, invalid hierarchy, missing quote, or length overflow.¶
401 UNAUTHORIZED: command issued while
unauthenticated, or action attempted without the required
team subscription.¶
404 UNKNOWN_USER "user_uuid": referenced user UUID does not
exist.¶
404 UNKNOWN_TEAM "team_uuid": referenced team UUID does not
exist.¶
404 UNKNOWN_CHANNEL "channel_uuid": referenced channel UUID does
not exist in the current hierarchy.¶
404 UNKNOWN_THREAD "thread_uuid": referenced thread UUID does not
exist in the current hierarchy.¶
404 UNKNOWN_REPLY "reply_uuid": referenced reply UUID does not
exist.¶
409 ALREADY_EXISTS: an entity with the same unique
name or title already exists in its scope.¶
500 INTERNAL_ERROR: unexpected server error.¶
Authentication in this subject is identity-based only and does not rely on passwords. The server MUST nevertheless enforce authorization rules strictly: unauthenticated sessions cannot inspect users or resources, and non-subscribers cannot access or receive team-scoped data.¶
The server SHOULD validate line length, quoted-string syntax, and UUID format before processing a command. Oversized payloads MUST be rejected to avoid parser abuse and buffer overflows.¶
Direct messages and persisted collaboration data SHOULD only be disclosed to authorized users. Save and restore logic MUST keep resource relationships intact so that a thread cannot be restored under the wrong channel or team.¶