The MCP protocol revisions this server knows, and which of them it speaks.
There is ONE table of known revisions (@table, newest first). Each revision
has a profile: a map of feature flags. Everything that depends on the
revision asks this module (profile/1, feature?/2) instead of comparing
revision strings, so a revision is one row here and nowhere else.
Flags
:structured_content- atools/callresult carriesstructuredContent;:output_schema- a tool descriptor carriesoutputSchema;:tool_title- a tool descriptor carriestitle;:server_title-serverInfocarriestitle.
Batching is not a flag: this server refuses a JSON-RPC batch under every
revision (PhoenixKit.API.MCP.Rpc).
Which revisions are served
By default every known revision. The application environment narrows and orders that set, read at call time (so it needs no recompile and no restart of anything but the config change):
config :phoenix_kit, :mcp_protocol_versions, ["2025-06-18", "2025-03-26"]The list is in preference order: latest/0 is its head, and negotiate/1
answers with it when the client asks for something this server does not
serve. An entry that is not in the table is ignored; a list that ends up
empty (or is not a list) is replaced by the default. Each of these is logged
once per node, as a warning that names the key and never the value.
A revision that is known but not enabled is answered like any unsupported
one: HTTP 400 with JSON-RPC -32600 on the MCP-Protocol-Version header, and
a lower revision from initialize.
Adding or retiring a revision
Retire one without a code change: leave it out of :mcp_protocol_versions.
Keep serving an older one when a newer one is added to the table: list the
older ones there.
Adding a revision is one @table entry with its flags, when its wire format
is one the code already produces (the same envelope, the same handshake, the
same result and descriptor shapes, differing at most in which of the flags
above are on). A revision that changes the wire format in any other way (a
different handshake, a new required field, another message shape; 2026-07-28
is such a revision) cannot be added by data: it needs code in the places
that read the flags (PhoenixKit.API.MCP, PhoenixKit.API.MCP.Shape,
PhoenixKit.API.MCP.Rpc), and a new flag where the code must branch.
For hosts and tests
config :phoenix_kit, :mcp_extra_revisions, [{"2027-01-01", %{...flags}}]
adds revisions to the table, for a host that has to speak one before core
does and for the tests of this mechanism. Flags that are left out are off;
an entry with a bad version, bad flags or the version of a built-in row is
ignored (the built-in row wins), with the same one-time warning.
Summary
Functions
Whether the profile of version has flag on. A revision that is not known has none.
The feature flags a profile has.
The revision a request without an MCP-Protocol-Version header is taken to be.
Every revision in the table (the built-in ones and :mcp_extra_revisions), newest first.
The most preferred revision this server speaks: the newest unless the configuration orders otherwise.
The revision initialize answers with: what the client asked for when this
server speaks it, else latest/0. Any term is accepted.
The profile of a known revision (enabled or not), nil for any other term.
The revisions this server speaks, in preference order.
Whether this server speaks version.
Types
Functions
Whether the profile of version has flag on. A revision that is not known has none.
@spec flags() :: [flag()]
The feature flags a profile has.
@spec implied() :: version()
The revision a request without an MCP-Protocol-Version header is taken to be.
@spec known() :: [version()]
Every revision in the table (the built-in ones and :mcp_extra_revisions), newest first.
@spec latest() :: version()
The most preferred revision this server speaks: the newest unless the configuration orders otherwise.
The revision initialize answers with: what the client asked for when this
server speaks it, else latest/0. Any term is accepted.
The profile of a known revision (enabled or not), nil for any other term.
@spec supported() :: [version()]
The revisions this server speaks, in preference order.
Every known revision unless :mcp_protocol_versions narrows or orders them.
Never empty.
Whether this server speaks version.