Skip to main content

pmcp/shared/
mod.rs

1//! Shared components used by both client and server.
2
3pub mod batch;
4pub mod context;
5/// The DEFAULT on-disk credential store — the gated I/O counterpart to
6/// [`credential_store`] below.
7///
8/// Gated on `not(wasm32)` AND `feature = "oauth"` because every item in it needs
9/// a filesystem, and `default_credential_path` needs the `oauth` feature's
10/// `dirs` dependency. It is a SEPARATE module rather than a gated half of
11/// `credential_store` so that the pure tier keeps its "no `#[cfg]` other than
12/// `cfg(test)`" property, which is what makes its wasm32 cleanliness reviewable
13/// at a glance. It knows nothing about the credential document's shape: the
14/// format, the schema migration and the migration report all stay next door.
15#[cfg(all(not(target_arch = "wasm32"), feature = "oauth"))]
16pub mod credential_file;
17/// Target-agnostic OAuth credential storage: the three-part key, the record,
18/// the document format, the schema 1 to 2 migration and the platform seam.
19///
20/// Ungated on purpose — a file under the user's home directory is unusable on
21/// AWS Lambda and per-container on Cloudflare Workers and Cloud Run, so
22/// credential storage lands behind a trait and everything a platform needs in
23/// order to implement that trait must compile where the `oauth` feature does
24/// not exist, on host AND wasm32. Its only imports are this crate's error type,
25/// `serde`, `async_trait`, `parking_lot` and the non-optional `url` crate. Do
26/// NOT "tidy" a target or feature gate onto it: a second copy of the document
27/// format and its migration is how a platform store and the CLI come to
28/// disagree about what a stored credential means. A gated FILE implementation
29/// is the deliberate counterpart and belongs in its own module. (Contrast the
30/// `#[cfg(not(target_arch = "wasm32"))]` peer/stdio entries elsewhere in this
31/// file; `oauth_validation` and `pkce` below carry the same rationale.)
32pub mod credential_store;
33// SMPL-02: the single largest severance win in `src/shared/`.
34//
35// `event_store.rs` is 421 lines of MCP 2025-11-25 SSE-resumability machinery —
36// the `Last-Event-ID` replay store, its resumption tokens and its retention
37// window. The 2026-07-28 transport states that resumable SSE streams via
38// `Last-Event-ID` are not supported, so on a `full-v2` build not one line of it
39// has a caller. Re-measured before this gate landed: ZERO consumers anywhere in
40// `src/`, `crates/`, `tests/`, `examples/`, `cargo-pmcp/` or `fuzz/` outside the
41// file itself and the re-export below. (The `EventStore`/`InMemoryEventStore`
42// that the integration tests DO use is a different, 3-method trait that lives in
43// `src/server/streamable_http_server.rs`.)
44//
45// GATED, NOT DELETED. Both items are PUBLIC API; removing them is a semver-major
46// change and belongs to SMPL-F1 / pmcp 3.0 — see `docs/v1-sunset-policy.md`. The
47// `#[cfg]` must stay on BOTH this declaration and the `pub use event_store::{…}`
48// re-export further down; gating only one of the two is a compile break.
49//
50// DO NOT "FINISH THE JOB" BY GATING THE SSE FILES (correction A-D03). Neither
51// `src/shared/sse_parser.rs` nor `src/shared/sse_optimized.rs` is v1-only: v2's
52// `subscriptions/listen` returns a live `text/event-stream`
53// (`src/server/streamable_http_server.rs`, whose subscribe handler REJECTS any
54// non-V2 era), so SSE framing and parsing are SHARED by both eras. Only
55// RESUMABILITY is v1-only. `src/shared/http_constants.rs` is likewise
56// deliberately ungated — per-constant gating is plan 117-13's job — and
57// `src/shared/session.rs` is unmeasured and deliberately left alone.
58#[cfg(feature = "v1-compat")]
59#[cfg_attr(docsrs, doc(cfg(feature = "v1-compat")))]
60/// v1-only SSE resumability: the `Last-Event-ID` replay store and its tokens.
61pub mod event_store;
62/// Hardened HTTP plumbing for this crate's OAuth/OIDC surfaces: the streaming
63/// bounded whole-body read every auth response is read through, and the
64/// discovery HTTP client whose redirect policy cannot be steered off the
65/// issuer's origin.
66///
67/// Gated on `feature = "http-client"` because every item in it takes or returns
68/// a `reqwest` type; the wasm32 build does not enable that feature and must not
69/// see this module. `pub(crate)` on purpose — the four auth files that consume
70/// it are all in-crate, and this hardening adds no public surface it does not
71/// need.
72#[cfg(feature = "http-client")]
73pub(crate) mod http_body_cap;
74pub mod http_utils;
75pub mod logging;
76pub mod middleware;
77pub mod middleware_presets;
78/// Target-agnostic OAuth authorization-RESPONSE validation (RFC 9207 `iss`,
79/// CSRF `state`).
80///
81/// Ungated on purpose — it must be callable from a Cloudflare Workers or
82/// Lambda redirect handler, where the `oauth` feature (and its `webbrowser` /
83/// `dirs` / `rand` dependencies) does not exist and does not build. Its only
84/// imports are this crate's error type and the non-optional `url` crate, so it
85/// compiles on host AND wasm32. Do NOT "tidy" a `cfg` onto it: a second copy of
86/// the RFC 9207 decision table is how a platform handler and the CLI come to
87/// disagree about what "valid" means. (Contrast the
88/// `#[cfg(not(target_arch = "wasm32"))]` peer/stdio entries elsewhere in this
89/// file, and note `pkce` below carries the same rationale for the same reason.)
90pub mod oauth_validation;
91/// Peer back-channel trait for server-to-client RPCs from inside request handlers.
92#[cfg(not(target_arch = "wasm32"))]
93pub mod peer;
94/// Target-agnostic one-slot pending-response buffer for one-shot transports.
95///
96/// Internal plumbing (`pub(crate)`) backing the `WasmHttpTransport`
97/// send→receive correlation; ungated so it host-tests under plain `cargo test`.
98pub(crate) mod pending_slot;
99/// Target-agnostic PKCE (RFC 7636) crypto helper (verifier/challenge/state).
100///
101/// Ungated on purpose — compiles on host AND wasm32 via `getrandom::fill`
102/// (contrast the `#[cfg(not(target_arch = "wasm32"))]` peer/stdio entries).
103pub mod pkce;
104pub mod protocol;
105pub mod protocol_helpers;
106#[cfg(not(target_arch = "wasm32"))]
107pub mod reconnect;
108pub mod session;
109pub mod simd_parsing;
110// Dead on wasm32 by CONFIGURATION, not by disuse: this module's consumers are the
111// native server/client tier (`src/server/core.rs`, `src/server/task_dispatch.rs`,
112// `src/client/mod.rs`), all of which are `#[cfg(not(target_arch = "wasm32"))]`. The
113// items are `pub(crate)` and very much alive natively, so they must NOT be deleted;
114// the wasm build simply has no callers for them. Scoped to wasm32 so genuine dead
115// code is still caught on every other target.
116#[cfg_attr(
117    any(target_arch = "wasm32", not(feature = "streamable-http")),
118    allow(dead_code)
119)]
120pub mod sse_parser;
121
122#[cfg(feature = "sse")]
123pub mod sse_optimized;
124
125#[cfg(not(target_arch = "wasm32"))]
126pub mod connection_pool;
127#[cfg(not(target_arch = "wasm32"))]
128pub mod stdio;
129pub mod transport;
130pub mod uri_template;
131
132// Cross-platform runtime abstraction
133pub mod runtime;
134
135// Platform-specific WebSocket modules
136#[cfg(all(feature = "websocket", not(target_arch = "wasm32")))]
137pub mod websocket;
138
139#[cfg(all(feature = "websocket-wasm", target_arch = "wasm32"))]
140pub mod wasm_websocket;
141
142#[cfg(target_arch = "wasm32")]
143pub mod wasm_http;
144
145#[cfg(all(feature = "http", not(target_arch = "wasm32")))]
146pub mod http;
147pub mod http_constants;
148
149#[cfg(all(feature = "streamable-http", not(target_arch = "wasm32")))]
150/// Streamable HTTP transport implementation for MCP.
151pub mod streamable_http;
152
153// Re-export commonly used types
154pub use batch::{BatchRequest, BatchResponse};
155pub use context::{ClientInfo, ContextPropagator, RequestContext};
156// The other half of the SMPL-02 `event_store` gate. Must carry the SAME `#[cfg]`
157// as the `pub mod event_store;` declaration above — gating one without the other
158// is a compile break, not a warning.
159#[cfg(feature = "v1-compat")]
160#[cfg_attr(docsrs, doc(cfg(feature = "v1-compat")))]
161pub use event_store::{
162    EventStore, EventStoreConfig, InMemoryEventStore, MessageDirection, ResumptionManager,
163    ResumptionState, ResumptionToken, StoredEvent,
164};
165#[cfg(all(not(target_arch = "wasm32"), feature = "logging"))]
166pub use logging::init_logging;
167pub use logging::{CorrelatedLogger, LogConfig, LogEntry, LogFormat, LogLevel};
168pub use middleware::{
169    AdvancedMiddleware, AuthMiddleware, CircuitBreakerMiddleware, CompressionMiddleware,
170    CompressionType, EnhancedMiddlewareChain, LoggingMiddleware, MetricsMiddleware, Middleware,
171    MiddlewareChain, MiddlewareContext, MiddlewarePriority, PerformanceMetrics,
172    RateLimitMiddleware, RetryMiddleware,
173};
174pub use protocol::{ProgressCallback, Protocol, ProtocolOptions, RequestOptions};
175pub use protocol_helpers::{
176    create_notification, create_request, parse_notification, parse_request,
177};
178#[cfg(not(target_arch = "wasm32"))]
179pub use reconnect::{ReconnectConfig, ReconnectGuard, ReconnectManager};
180pub use session::{Session, SessionConfig, SessionManager};
181#[cfg(not(target_arch = "wasm32"))]
182pub use stdio::StdioTransport;
183pub use transport::{Transport, TransportMessage};
184pub use uri_template::UriTemplate;
185
186#[cfg(all(feature = "websocket", not(target_arch = "wasm32")))]
187pub use websocket::{WebSocketConfig, WebSocketTransport};
188
189#[cfg(all(feature = "websocket-wasm", target_arch = "wasm32"))]
190pub use wasm_websocket::{WasmWebSocketConfig, WasmWebSocketTransport};
191
192#[cfg(target_arch = "wasm32")]
193pub use wasm_http::{WasmHttpClient, WasmHttpConfig, WasmHttpTransport};
194
195#[cfg(all(feature = "http", not(target_arch = "wasm32")))]
196pub use http::{HttpConfig, HttpTransport};
197
198#[cfg(all(feature = "streamable-http", not(target_arch = "wasm32")))]
199pub use streamable_http::{StreamableHttpTransport, StreamableHttpTransportConfig};
200
201// Why: `OptimizedSseTransport` is deprecated on purpose (plan 113.1-03, D-01)
202// but is NOT removed — retiring a public item is a 3.0 action, and this
203// milestone's additivity claim is "zero removed public items". The `deprecated`
204// lint fires on a `pub use` re-export within the defining crate, and `make lint`
205// runs with `-D warnings`, so the crate must allow it to compile its own
206// retained transport. `OptimizedSseConfig` is deliberately NOT deprecated.
207#[allow(deprecated)]
208#[cfg(feature = "sse")]
209pub use sse_optimized::{OptimizedSseConfig, OptimizedSseTransport};
210
211#[cfg(not(target_arch = "wasm32"))]
212pub use connection_pool::{
213    ConnectionId, ConnectionPool, ConnectionPoolConfig, HealthStatus, LoadBalanceStrategy,
214    PoolStats, PooledTransport,
215};
216
217pub use simd_parsing::{
218    CpuFeatures, ParsingMetrics, SimdBase64, SimdHttpHeaderParser, SimdJsonParser, SimdSseParser,
219};