Wymcp. Plugs. Era
(Wymcp v0.1.1)
View Source
Legacy-only
Era classification exists only because a second era does. This module is removed wholesale at the legacy decommission.
Era classification (docs/glossary.md, era classification): tags every
POST with the era whose lane serves it — conn.assigns[:wymcp_era],
:modern or :legacy — and rejects the two era-mix shapes with 400.
Runs after the three wire checks (they are era-invariant, and the
singleton-header check guarantees at most one Mcp-Session-Id before
this plug reads it) and before Wymcp.Plugs.Session, which passes
modern-classified requests through untouched.
The classification table — the modern protocol fields
(docs/glossary.md, protocol fields) are modern-era evidence;
initialize and Mcp-Session-Id are legacy-era evidence:
| Signals on the request | Classification |
|---|---|
protocol field(s), no session header, not initialize | :modern |
initialize, no protocol fields | :legacy |
Mcp-Session-Id, no protocol fields | :legacy (session lookup as before) |
protocol fields + Mcp-Session-Id | reject 400 — era mix |
initialize + protocol fields | reject 400 — era mix |
| none of the above | :legacy (Wymcp.Plugs.Session's missing-header rejection names both eras' next actions) |
Either required protocol field's presence classifies modern;
Wymcp.Plugs.ProtocolFields downstream enforces that both are present
and well-typed. Era-mix fails closed rather than ignoring the legacy
artifact: the spec's ignore rule is written for modern-only servers,
where no legacy lane exists to mis-route into — at a dual-era server a
client sending both signals may believe in session state the modern lane
would silently ignore. A request carrying all three signals meets the
session-header rejection first (the table's row order is the check
order). Headers are never era evidence (MCP-Protocol-Version binding
is a planned design of its own); only body fields and Mcp-Session-Id
presence are read here.