Internet-Draft RFC MyTeams (MTP) April 2026
Zarrillo, et al. Expires 17 October 2026 [Page]
Workgroup:
Network Working Group
Published:
Intended Status:
Informational
Expires:
Authors:
V.Z. Zarrillo
M.Y. Yildirim
M.T. Tutti

RFC MyTeams (MTP)

Abstract

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.

Status of This Memo

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.

Table of Contents

1. Introduction

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.

2. Terminology

The following terms are used throughout this document:

3. Protocol Behavior

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.

4. Message Format

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
Figure 1

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.

5. Command Definitions

5.1. LOGIN

C: LOGIN "user_name"
S: 200 OK "uuid"
Figure 2

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.

5.1.1. Responses

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.

5.2. LOGOUT

C: LOGOUT
S: 200 OK
Figure 3

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.

5.2.1. Responses

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.

5.3. USERS

C: USERS
S: 200 "user_uuid" "user_name" "status"
   [| "user_uuid" "user_name" "status" ...]
Figure 4

Returns the list of all users known by the domain together with their connection status. This command requires an authenticated session.

5.3.1. Responses

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.

5.4. USER

C: USER "user_uuid"
S: 200 "user_uuid" "user_name" "status"
Figure 5

Returns the details of a single user identified by "user_uuid". The caller MUST be authenticated.

5.4.1. Responses

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.

5.5. SEND

C: SEND "user_uuid" "message_body"
S: 200 OK
Figure 6

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.

5.5.1. Responses

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.

5.6. MESSAGES

C: MESSAGES "user_uuid"
S: 200 "sender_uuid" "message_timestamp" "message_body"
   [| "sender_uuid" "message_timestamp" "message_body" ...]
Figure 7

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.

5.6.1. Responses

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.

5.7. SUBSCRIBE

C: SUBSCRIBE "team_uuid" "user_uuid"
S: 200 OK
Figure 8

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.

5.7.1. Responses

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.

5.8. UNSUBSCRIBE

C: UNSUBSCRIBE "team_uuid" "user_uuid"
S: 200 OK
Figure 9

Removes the user identified by "user_uuid" from the subscriber set of the specified team.

5.8.1. Responses

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.

5.9. SUBSCRIBED

C: SUBSCRIBED "user_uuid"
S: 200 "team_uuid"[|"team_uuid"...]
Figure 10

Returns the UUID list of teams to which the user identified by "user_uuid" is subscribed, separated by pipe characters.

5.9.1. Responses

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.

5.10. SUBSCRIBEDTEAM

C: SUBSCRIBEDTEAM "team_uuid"
S: 200 "user_uuid" "user_name" "status"
   [| "user_uuid" "user_name" "status" ...]
Figure 11

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.

5.10.1. Responses

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.

5.11. CREATETEAM

C: CREATETEAM "team_name" "team_description"
S: 200 OK "team_uuid"
Figure 12

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.

5.11.1. Responses

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.

5.12. CREATECHANNEL

C: CREATECHANNEL "team_uuid" "channel_name" "channel_description"
S: 200 OK "channel_uuid"
Figure 13

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.

5.12.1. Responses

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.

5.13. CREATETHREAD

C: CREATETHREAD "team_uuid" "channel_uuid" "thread_title"
   "thread_message"
S: 200 OK "thread_uuid"
Figure 14

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.

5.13.1. Responses

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.

5.14. CREATECOMMENT

C: CREATECOMMENT "team_uuid" "channel_uuid" "thread_uuid"
   "comment_body"
S: 200 OK "reply_uuid"
Figure 15

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.

5.14.1. Responses

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.

5.15. LISTTEAM

C: LISTTEAM
S: 200 "team_uuid"[|"team_uuid"...]
Figure 16

Lists all teams in the domain.

5.15.1. Responses

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.

5.16. LISTCHANNEL

C: LISTCHANNEL "team_uuid"
S: 200 "channel_uuid"[|"channel_uuid"...]
Figure 17

Lists all channels with the team provided.

The caller MUST be subscribed to the referenced team.

5.16.1. Responses

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.

5.17. LISTTHREAD

C: LISTTHREAD "channel_uuid"
S: 200 "thread_uuid"[|"thread_uuid"...]
Figure 18

Lists all threads with the channel provided.

The caller MUST be subscribed to the team that owns the referenced channel.

5.17.1. Responses

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.

5.18. LISTREPLY

C: LISTREPLY "thread_uuid"
S: 200 "reply_uuid"[|"reply_uuid"...]
Figure 19

Lists all replies with the thread provided.

The caller MUST be subscribed to the team that owns the referenced thread.

5.18.1. Responses

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.

5.19. INFOUSER

C: INFOUSER "user_uuid"
S: 200 "user_uuid" "user_name" "status"
Figure 20

Returns the details of the user identified by "user_uuid".

5.19.1. Responses

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.

5.20. INFOTEAM

C: INFOTEAM "team_uuid"
S: 200 "team_uuid" "team_name" "team_description"
Figure 21

Returns the selected team details provided in the parameter.

The caller MUST be subscribed to the referenced team.

5.20.1. Responses

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.

5.21. INFOCHANNEL

C: INFOCHANNEL "channel_uuid"
S: 200 "channel_uuid" "channel_name" "channel_description"
Figure 22

Returns the information about the channel provided.

The caller MUST be subscribed to the team that owns the referenced channel.

5.21.1. Responses

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.

5.22. INFOTHREAD

C: INFOTHREAD "thread_uuid"
S: 200 "thread_uuid" "author_uuid" "thread_timestamp" "thread_title"
   "thread_message"
Figure 23

Returns the information about the thread provided.

The caller MUST be subscribed to the team that owns the referenced thread.

5.22.1. Responses

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.

5.23. INFOREPLY

C: INFOREPLY "reply_uuid"
S: 200 "reply_uuid" "author_uuid" "reply_timestamp" "reply_body"
Figure 24

Returns the information about the reply provided.

The caller MUST be subscribed to the team that owns the referenced reply.

5.23.1. Responses

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.

6. Persistent Data

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
    └── ...
Figure 25

6.1. Global File Structure

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             |
    | ...                  |
    +----------------------+
Figure 26

6.2. Record Format

Each record MUST follow a TLV (Type-Length-Value) structure.

    +----------------------+
    | Type (2B)            |
    | Value Length (4B)    |
    | Value (variable)     |
    +----------------------+
Figure 27

6.3. Entity Types

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

6.4. User Record

    +----------------------+
    | UUID (16B)           |
    | Name Length (2B)     |
    | Name (variable)      |
    +----------------------+
Figure 28

6.5. Team Record

    +------------------------+
    | UUID (16B)             |
    | Name Length (2B)       |
    | Name (variable)        |
    | Description Length (2B)|
    | Description (variable) |
    | Created At (8B)        |
    +------------------------+
Figure 29

6.6. Channel Record

    +------------------------+
    | UUID (16B)             |
    | Team UUID (16B)        |
    | Name Length (2B)       |
    | Name (variable)        |
    | Description Length (2B)|
    | Description (variable) |
    | Created At (8B)        |
    +------------------------+
Figure 30

6.7. Thread Record

    +----------------------+
    | UUID (16B)           |
    | Channel UUID (16B)   |
    | Author UUID (16B)    |
    | Title Length (2B)    |
    | Title (variable)     |
    | Message Length (4B)  |
    | Message (variable)   |
    | Created At (8B)      |
    +----------------------+
Figure 31

6.8. Reply Record

    +----------------------+
    | UUID (16B)           |
    | Thread UUID (16B)    |
    | Author UUID (16B)    |
    | Content Length (4B)  |
    | Content (variable)   |
    | Timestamp (8B)       |
    +----------------------+
Figure 32

6.9. Subscription Record

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)      |
    +----------------------+
Figure 33

6.10. Direct Message Record

    +----------------------+
    | UUID (16B)           |
    | Sender UUID (16B)    |
    | Receiver UUID (16B)  |
    | Content Length (4B)  |
    | Content (variable)   |
    | Timestamp (8B)       |
    +----------------------+
Figure 34

7. Error Handling

The server MUST reject malformed or unauthorized requests without mutating persistent state.

8. Security Considerations

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.