1#![forbid(unsafe_code)]
40#![allow(dead_code)]
41
42pub mod common_types;
43pub mod extensions;
44#[cfg(feature = "jose")]
45pub mod jose;
46mod jsonrpc;
47#[cfg(feature = "apps")]
48pub mod mcp_apps_bridge;
49mod messages;
50pub mod methods;
51pub mod protocol_policy;
52pub mod protocol_version;
53mod result;
54pub mod schema;
55pub mod server_discovery;
56#[cfg(feature = "tasks")]
57pub mod tasks_extension;
58mod types;
59pub mod uri_template;
60
61pub use common_types::JsonInteger;
62pub use extensions::{
63 ClientExtensionDiscovery, ExtensionDescriptor, ExtensionDescriptorRegistry, ExtensionDirection,
64 ExtensionDiscovery, ExtensionFallbackPolicy, ExtensionHttpEraDisposition, ExtensionId,
65 ExtensionMethodDescriptor, ExtensionNegotiationResolver, ExtensionNotificationDescriptor,
66 ExtensionRegistryError, ExtensionRegistryReceipt, ExtensionRoutingHeaderDescriptor,
67 ExtensionSettings, ExtensionSettingsCompatibilityResolver, ExtensionSettingsResolution,
68 ExtensionSettingsSchema, MAX_EXTENSION_DESCRIPTORS, MAX_EXTENSION_ID_BYTES,
69 MAX_EXTENSION_REGISTRY_CANONICAL_BYTES, MAX_EXTENSION_SETTINGS_ENTRIES,
70 MAX_EXTENSION_SETTINGS_KEY_BYTES, MAX_EXTENSION_SETTINGS_NESTING,
71 MAX_EXTENSION_SETTINGS_VALUE_BYTES, MAX_MCP_APPS_MIME_TYPE_BYTES, MAX_MCP_APPS_MIME_TYPES,
72 MCP_APPS_ACTIVATION_PREDICATE_ID, MCP_APPS_CLIENT_SETTINGS_SCHEMA_ID,
73 MCP_APPS_DOWNLOAD_FILE_METHOD, MCP_APPS_HOST_CONTEXT_CHANGED_NOTIFICATION,
74 MCP_APPS_HTML_MIME_TYPE, MCP_APPS_INITIALIZE_METHOD, MCP_APPS_INITIALIZED_NOTIFICATION,
75 MCP_APPS_MESSAGE_METHOD, MCP_APPS_NEGOTIATION_RESOLVER_ID, MCP_APPS_OPEN_LINK_METHOD,
76 MCP_APPS_REQUEST_DISPLAY_MODE_METHOD, MCP_APPS_REQUEST_TEARDOWN_NOTIFICATION,
77 MCP_APPS_RESOURCE_TEARDOWN_METHOD, MCP_APPS_SANDBOX_PROXY_READY_NOTIFICATION,
78 MCP_APPS_SANDBOX_RESOURCE_READY_NOTIFICATION, MCP_APPS_SERVER_SETTINGS_SCHEMA_ID,
79 MCP_APPS_SIZE_CHANGED_NOTIFICATION, MCP_APPS_TOOL_CANCELLED_NOTIFICATION,
80 MCP_APPS_TOOL_INPUT_NOTIFICATION, MCP_APPS_TOOL_INPUT_PARTIAL_NOTIFICATION,
81 MCP_APPS_TOOL_RESULT_NOTIFICATION, MCP_APPS_UPDATE_MODEL_CONTEXT_METHOD, McpAppsClientSettings,
82 McpAppsNegotiationResolver, OFFICIAL_MCP_APPS_EXTENSION_ID,
83 RejectingExtensionNegotiationResolver, ServerExtensionDiscovery, StdioCorrelationDescriptor,
84 official_mcp_apps_descriptor, official_mcp_apps_empty_server_settings,
85 official_mcp_apps_extension_id, official_mcp_apps_negotiation_resolver,
86 register_official_mcp_apps_extension, resolve_official_mcp_apps_settings,
87};
88#[cfg(feature = "tasks")]
89pub use extensions::{
90 OFFICIAL_TASKS_EMPTY_SETTINGS_CODEC_ID, OFFICIAL_TASKS_EMPTY_SETTINGS_SCHEMA_ID,
91 OFFICIAL_TASKS_EXTENSION_ID, OFFICIAL_TASKS_METHODS, OFFICIAL_TASKS_NOTIFICATION,
92 OFFICIAL_TASKS_RESULT_DISCRIMINATOR, OfficialTasksNegotiationResolver,
93 TasksNegotiationResolver, official_tasks_descriptor, official_tasks_empty_settings,
94 official_tasks_extension_id, register_official_tasks_extension,
95};
96pub use jsonrpc::{
97 ClientIngressFailureScope, CorrelationKey, JSONRPC_VERSION, JsonRpcAdmissionError,
98 JsonRpcEndpointRole, JsonRpcError, JsonRpcMessage, JsonRpcMessageDirection, JsonRpcRequest,
99 JsonRpcResponse, JsonRpcResponseAdmission, MAX_JSONRPC_STRING_ID_ENCODED_BYTES,
100 MAX_RAW_JSON_AGGREGATE_NUMBER_BYTES, MAX_RAW_JSON_CONTAINER_ENTRIES, MAX_RAW_JSON_EXPONENT,
101 MAX_RAW_JSON_NESTING_DEPTH, MAX_RAW_JSON_NUMBER_BYTES, RawJsonAdmissionError,
102 RawJsonRpcDisposition, RequestId, UncorrelatedJsonRpcErrorResponse, admit_raw_jsonrpc_document,
103 decode_strict_jsonrpc_message, decode_strict_jsonrpc_response, dispose_raw_jsonrpc_failure,
104};
105#[cfg(feature = "apps")]
106pub use mcp_apps_bridge::*;
107pub use messages::*;
108pub use methods::SERVER_DISCOVER;
109pub use protocol_version::{
110 FINAL_PROTOCOL_VERSION, FinalHttpRequestMetadata, FinalProtocolVersion, FinalRequestAdmission,
111 HEADER_MISMATCH_ERROR_CODE, HeaderMismatchError, HeaderMismatchReason,
112 MAX_REQUIRED_CAPABILITIES_ERROR_DATA_BYTES, MCP_METHOD_HEADER, MCP_NAME_HEADER,
113 MCP_PROTOCOL_VERSION_HEADER, MISSING_REQUIRED_CLIENT_CAPABILITY_ERROR_CODE,
114 MissingRequiredClientCapabilityError, ProtocolVersionError, RequestAdmissionError,
115 RequestVersionMetadata, RequiredCapabilitiesError, SUPPORTED_FINAL_PROTOCOL_VERSIONS,
116 UNSUPPORTED_PROTOCOL_VERSION_ERROR_CODE, UnsupportedProtocolVersionError,
117 admit_final_http_request, admit_final_request, validate_final_protocol_version,
118};
119pub use result::*;
120pub use schema::{
121 AdmittedFinalFormSchema, AdmittedSchema, FinalCoreResultType, SchemaAdmissionError,
122 ValidationError, ValidationResult, admit_final_form_schema, admit_final_schema, validate,
123 validate_final_core_result, validate_strict,
124};
125pub use server_discovery::{
126 DiscoveryCacheHints, MAX_SERVER_INSTRUCTIONS_BYTES, SERVER_DISCOVER_METHOD,
127 SERVER_DISCOVER_SERVER_INFO_META_KEY, SERVER_DISCOVER_SUPPORTED_VERSIONS, ServerBehavior,
128 ServerBehaviorRegistry, ServerDiscoverCapabilities, ServerDiscoverRequest,
129 ServerDiscoverResult, ServerDiscoveryError, ServerInstructionError, ServerInstructions,
130};
131#[cfg(feature = "tasks")]
132pub use tasks_extension::{
133 CancelTaskParams as FinalCancelTaskParams, CancelTaskResult as FinalCancelTaskResult,
134 CompleteTaskResult, CreateTaskResult, EmptyTaskResult, FinalTaskCallToolResult, FinalTaskError,
135 GetTaskParams as FinalGetTaskParams, GetTaskResult as FinalGetTaskResult, MAX_TASK_ID_BYTES,
136 MAX_TASK_INPUT_MAP_ENTRIES, MAX_TASK_SUBSCRIPTION_IDS, RELATED_TASK_META_KEY, TASK_CANCEL,
137 TASK_GET, TASK_STATUS_NOTIFICATION, TASK_SUBSCRIPTION_IDS_KEY, TASKS_EXTENSION, Task, TaskBase,
138 TaskDuration, TaskId as FinalTaskId, TaskInputLedger, TaskInputRequests, TaskInputResponses,
139 TaskMethodRequest, TaskRequestMeta, TaskStatus as FinalTaskStatus, TaskStatusNotification,
140 TaskStatusNotificationParams as FinalTaskStatusNotificationParams, TaskTimestamp,
141 TaskWireError, UpdateTaskParams, UpdateTaskResult, set_task_subscription_ids,
142 task_subscription_ids,
143};
144pub use types::*;
145pub use uri_template::{
146 MAX_URI_TEMPLATE_BYTES, MAX_URI_TEMPLATE_COMPOSITE_ITEMS,
147 MAX_URI_TEMPLATE_EXPANSION_OUTPUT_BYTES, MAX_URI_TEMPLATE_EXPRESSIONS, MAX_URI_TEMPLATE_PARTS,
148 MAX_URI_TEMPLATE_PREFIX_LENGTH, MAX_URI_TEMPLATE_VALUE_BYTES,
149 MAX_URI_TEMPLATE_VARIABLE_NAME_BYTES, MAX_URI_TEMPLATE_VARIABLES_PER_EXPRESSION,
150 ReversibleResourceTemplate, TemplateValue, TemplateValues, UriTemplate, UriTemplateError,
151 UriTemplateExpansionLimits, UriTemplateExpression, UriTemplateModifier, UriTemplateOperator,
152 UriTemplatePart,
153};
154
155#[cfg(test)]
159#[test]
160fn fnd_03_policy_receipts_positive() {
161 protocol_policy::tests::fnd_03_policy_receipts_positive();
162}
163
164#[cfg(test)]
165#[test]
166fn fnd_03_policy_receipts_planted_negative() {
167 protocol_policy::tests::fnd_03_policy_receipts_planted_negative();
168}
169
170#[cfg(test)]
171#[test]
172fn fnd_03_era_classification_positive() {
173 protocol_policy::tests::fnd_03_era_classification_positive();
174}
175
176#[cfg(test)]
177#[test]
178fn fnd_03_era_classification_planted_negative() {
179 protocol_policy::tests::fnd_03_era_classification_planted_negative();
180}
181
182#[cfg(test)]
183#[test]
184fn prt_03_i_positive() {
185 let required_capabilities = ClientCapabilities {
186 roots: Some(RootsCapability { list_changed: true }),
187 ..ClientCapabilities::default()
188 };
189 let metadata = FinalRequestMeta::new(required_capabilities.clone());
190 let admission = admit_final_http_request(FinalHttpRequestMetadata {
191 version: metadata.version_metadata(Some(FINAL_PROTOCOL_VERSION)),
192 header_method: Some(SERVER_DISCOVER),
193 body_method: Some(SERVER_DISCOVER),
194 header_name: None,
195 body_name: None,
196 })
197 .expect("canonical final metadata and server discovery must be admitted");
198 let missing =
199 MissingRequiredClientCapabilityError::from_client_capabilities(&required_capabilities)
200 .expect("typed required capabilities must encode as final error data");
201
202 assert_eq!(FINAL_PROTOCOL_VERSION, "2026-07-28");
203 assert_eq!(SERVER_DISCOVER, SERVER_DISCOVER_METHOD);
204 assert_eq!(MCP_PROTOCOL_VERSION_HEADER, "MCP-Protocol-Version");
205 assert_eq!(MCP_METHOD_HEADER, "Mcp-Method");
206 assert_eq!(MCP_NAME_HEADER, "Mcp-Name");
207 assert_eq!(
208 admission.protocol_version().as_str(),
209 FINAL_PROTOCOL_VERSION
210 );
211 assert_eq!(missing.http_status(), 400);
212 assert_eq!(
213 missing.jsonrpc_error_code(),
214 MISSING_REQUIRED_CLIENT_CAPABILITY_ERROR_CODE
215 );
216 assert_eq!(
217 missing.canonical_error_data(),
218 serde_json::json!({"requiredCapabilities": {"roots": {"listChanged": true}}})
219 );
220}
221
222#[cfg(test)]
223#[test]
224fn prt_03_i_planted_negative() {
225 let metadata = FinalRequestMeta::new(ClientCapabilities {
226 roots: Some(RootsCapability { list_changed: true }),
227 ..ClientCapabilities::default()
228 });
229 let wire_before = serde_json::to_value(&metadata).expect("metadata serializes");
230 let error = admit_final_http_request(FinalHttpRequestMetadata {
231 version: metadata.version_metadata(Some("2025-11-25")),
232 header_method: Some(SERVER_DISCOVER),
233 body_method: Some(SERVER_DISCOVER),
234 header_name: None,
235 body_name: None,
236 })
237 .expect_err("changing only the protocol header must reject the request");
238
239 assert!(
240 matches!(&error, RequestAdmissionError::HeaderMismatch(_)),
241 "a mismatched version mirror must precede unsupported-version classification"
242 );
243 let RequestAdmissionError::HeaderMismatch(error) = error else {
244 return;
245 };
246 assert_eq!(
247 error.reason(),
248 HeaderMismatchReason::HeaderBodyVersionMismatch
249 );
250 assert_eq!(error.http_status(), 400);
251 assert_eq!(error.jsonrpc_error_code(), HEADER_MISMATCH_ERROR_CODE);
252 assert_eq!(error.canonical_error_data(), None);
253 assert_eq!(
254 serde_json::to_value(&metadata).expect("metadata remains serializable"),
255 wire_before
256 );
257}