Description
The crate models many distinct identifier concepts — session id, task id, tool-use id, elicitation id, OAuth client id, SSE event id / stream id — but represents essentially all of them as bare String or Arc<str>, or as plain type aliases over those (pub type SessionId = Arc<str>, pub type EventId = String, pub type StreamId = String). A pub type X = Y alias is fully interchangeable with Y and with any other alias of Y at the type-checker level, so it provides no protection against passing one id kind where another is expected. As the protocol surface grows (mrtr, task, request-state), the number of distinct id-shaped String parameters keeps growing, and the risk of a silent argument-order mix-up grows with it.
Reproduction Steps
rg -n "_id: (String|Arc<str>)|Id\s*=\s*(String|Arc<str>)" crates/rmcp/src
- Observe multiple unrelated identifier fields (
task_id, tool_use_id, elicitation_id, client_id, last_event_id) typed as plain String, alongside SessionId/EventId/StreamId aliases that are also structurally just Arc<str>/String.
- Any function taking two or more of these ids in sequence (e.g. something taking both a
session_id: Arc<str> and a stream_id: String) compiles fine even if the arguments are swapped at a call site — the compiler cannot catch it.
Expected Behavior
Distinct identifier domains are represented as distinct newtypes (e.g. struct SessionId(Arc<str>), struct TaskId(String)), so swapping two id arguments of the same primitive shape is a compile error, not a runtime bug.
Actual Behavior
Identifiers are bare primitives or transparent type aliases; nothing in the type system distinguishes a TaskId from a SessionId from an EventId.
Environment
- Version: v3.1.2 (current
main, commit 02c62ae)
- Features: N/A (affects
model, task_manager, transport/auth.rs, transport/streamable_http_client.rs, transport/streamable_http_server/session/* regardless of feature set)
Locations
crates/rmcp/src/transport/common/server_side_http.rs:14 — pub type SessionId = Arc<str>;
crates/rmcp/src/transport/streamable_http_server/session/store.rs:10,13 — pub type EventId = String; / pub type StreamId = String;
crates/rmcp/src/model.rs:4239,4273,4310, crates/rmcp/src/model/task.rs:50, crates/rmcp/src/task_manager.rs:54 — task_id: String (repeated, no shared type)
crates/rmcp/src/model/content.rs:207 — tool_use_id: String
crates/rmcp/src/model.rs:3596,3705 — elicitation_id: String
crates/rmcp/src/transport/auth.rs:210,238,670,922,930,1055 — client_id: String
Upstream
None found — searched modelcontextprotocol/rust-sdk issues and PRs (all states) for "newtype session id task id" and "newtype id" with no matches.
Logs / Evidence
N/A — static analysis finding, no runtime reproduction needed.
Description
The crate models many distinct identifier concepts — session id, task id, tool-use id, elicitation id, OAuth client id, SSE event id / stream id — but represents essentially all of them as bare
StringorArc<str>, or as plain type aliases over those (pub type SessionId = Arc<str>,pub type EventId = String,pub type StreamId = String). Apub type X = Yalias is fully interchangeable withYand with any other alias ofYat the type-checker level, so it provides no protection against passing one id kind where another is expected. As the protocol surface grows (mrtr, task, request-state), the number of distinct id-shapedStringparameters keeps growing, and the risk of a silent argument-order mix-up grows with it.Reproduction Steps
rg -n "_id: (String|Arc<str>)|Id\s*=\s*(String|Arc<str>)" crates/rmcp/srctask_id,tool_use_id,elicitation_id,client_id,last_event_id) typed as plainString, alongsideSessionId/EventId/StreamIdaliases that are also structurally justArc<str>/String.session_id: Arc<str>and astream_id: String) compiles fine even if the arguments are swapped at a call site — the compiler cannot catch it.Expected Behavior
Distinct identifier domains are represented as distinct newtypes (e.g.
struct SessionId(Arc<str>),struct TaskId(String)), so swapping two id arguments of the same primitive shape is a compile error, not a runtime bug.Actual Behavior
Identifiers are bare primitives or transparent type aliases; nothing in the type system distinguishes a
TaskIdfrom aSessionIdfrom anEventId.Environment
main, commit 02c62ae)model,task_manager,transport/auth.rs,transport/streamable_http_client.rs,transport/streamable_http_server/session/*regardless of feature set)Locations
crates/rmcp/src/transport/common/server_side_http.rs:14—pub type SessionId = Arc<str>;crates/rmcp/src/transport/streamable_http_server/session/store.rs:10,13—pub type EventId = String;/pub type StreamId = String;crates/rmcp/src/model.rs:4239,4273,4310,crates/rmcp/src/model/task.rs:50,crates/rmcp/src/task_manager.rs:54—task_id: String(repeated, no shared type)crates/rmcp/src/model/content.rs:207—tool_use_id: Stringcrates/rmcp/src/model.rs:3596,3705—elicitation_id: Stringcrates/rmcp/src/transport/auth.rs:210,238,670,922,930,1055—client_id: StringUpstream
None found — searched
modelcontextprotocol/rust-sdkissues and PRs (all states) for "newtype session id task id" and "newtype id" with no matches.Logs / Evidence
N/A — static analysis finding, no runtime reproduction needed.