From 0a70ed663fa1a99cf2c595dccefe4526f17fbd6d Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Fri, 2 May 2025 14:38:59 -0700 Subject: [PATCH] fix: ensure jsonrpc field is serialized as "2.0" --- codex-rs/mcp-types/generate_mcp_types.py | 23 ++++++++++++++++++----- codex-rs/mcp-types/src/lib.rs | 15 +++++++++++++++ codex-rs/mcp-types/tests/initialize.rs | 2 ++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/codex-rs/mcp-types/generate_mcp_types.py b/codex-rs/mcp-types/generate_mcp_types.py index f613aa74eb..6066423f55 100755 --- a/codex-rs/mcp-types/generate_mcp_types.py +++ b/codex-rs/mcp-types/generate_mcp_types.py @@ -13,6 +13,8 @@ from pathlib import Path # Helper first so it is defined when other functions call it. from typing import Any, Literal +SCHEMA_VERSION = "2025-03-26" +JSONRPC_VERSION = "2.0" STANDARD_DERIVE = "#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]\n" @@ -30,7 +32,7 @@ def main() -> int: num_args = len(sys.argv) if num_args == 1: schema_file = ( - Path(__file__).resolve().parent / "schema" / "2025-03-26" / "schema.json" + Path(__file__).resolve().parent / "schema" / SCHEMA_VERSION / "schema.json" ) elif num_args == 2: schema_file = Path(sys.argv[1]) @@ -61,6 +63,9 @@ use serde::Serialize; use serde::de::DeserializeOwned; use std::convert::TryFrom; +pub const MCP_SCHEMA_VERSION: &str = "{SCHEMA_VERSION}"; +pub const JSONRPC_VERSION: &str = "{JSONRPC_VERSION}"; + /// Paired request/response types for the Model Context Protocol (MCP). pub trait ModelContextProtocolRequest { const METHOD: &'static str; @@ -74,6 +79,8 @@ pub trait ModelContextProtocolNotification { type Params: DeserializeOwned + Serialize + Send + Sync + 'static; } +fn default_jsonrpc() -> String {{ JSONRPC_VERSION.to_owned() }} + """ ] definitions = schema_json["definitions"] @@ -245,10 +252,6 @@ class StructField: serde: str | None = None def append(self, out: list[str], supports_const: bool) -> None: - # Omit these for now. - if self.name == "jsonrpc": - return - if self.serde: out.append(f" {self.serde}\n") if self.viz == "const": @@ -273,6 +276,16 @@ def define_struct( if prop_name == "_meta": # TODO? continue + elif prop_name == "jsonrpc": + fields.append( + StructField( + "pub", + "jsonrpc", + "String", # cannot use `&'static str` because of Deserialize + '#[serde(rename = "jsonrpc", default = "default_jsonrpc")]', + ) + ) + continue prop_type = map_type(prop, prop_name, name) if prop_name not in required_props: diff --git a/codex-rs/mcp-types/src/lib.rs b/codex-rs/mcp-types/src/lib.rs index 4ae0fa09cf..317fb279a3 100644 --- a/codex-rs/mcp-types/src/lib.rs +++ b/codex-rs/mcp-types/src/lib.rs @@ -10,6 +10,9 @@ use serde::Deserialize; use serde::Serialize; use std::convert::TryFrom; +pub const MCP_SCHEMA_VERSION: &str = "2025-03-26"; +pub const JSONRPC_VERSION: &str = "2.0"; + /// Paired request/response types for the Model Context Protocol (MCP). pub trait ModelContextProtocolRequest { const METHOD: &'static str; @@ -23,6 +26,10 @@ pub trait ModelContextProtocolNotification { type Params: DeserializeOwned + Serialize + Send + Sync + 'static; } +fn default_jsonrpc() -> String { + JSONRPC_VERSION.to_owned() +} + /// Optional annotations for the client. The client can use annotations to inform how objects are used or displayed #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct Annotations { @@ -370,6 +377,8 @@ pub type JSONRPCBatchResponse = Vec; pub struct JSONRPCError { pub error: JSONRPCErrorError, pub id: RequestId, + #[serde(rename = "jsonrpc", default = "default_jsonrpc")] + pub jsonrpc: String, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] @@ -394,6 +403,8 @@ pub enum JSONRPCMessage { /// A notification which does not expect a response. #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct JSONRPCNotification { + #[serde(rename = "jsonrpc", default = "default_jsonrpc")] + pub jsonrpc: String, pub method: String, pub params: Option, } @@ -402,6 +413,8 @@ pub struct JSONRPCNotification { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct JSONRPCRequest { pub id: RequestId, + #[serde(rename = "jsonrpc", default = "default_jsonrpc")] + pub jsonrpc: String, pub method: String, pub params: Option, } @@ -410,6 +423,8 @@ pub struct JSONRPCRequest { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct JSONRPCResponse { pub id: RequestId, + #[serde(rename = "jsonrpc", default = "default_jsonrpc")] + pub jsonrpc: String, pub result: Result, } diff --git a/codex-rs/mcp-types/tests/initialize.rs b/codex-rs/mcp-types/tests/initialize.rs index e857f8db3e..12e7f0f936 100644 --- a/codex-rs/mcp-types/tests/initialize.rs +++ b/codex-rs/mcp-types/tests/initialize.rs @@ -5,6 +5,7 @@ use mcp_types::InitializeRequestParams; use mcp_types::JSONRPCMessage; use mcp_types::JSONRPCRequest; use mcp_types::RequestId; +use mcp_types::JSONRPC_VERSION; use serde_json::json; #[test] @@ -30,6 +31,7 @@ fn deserialize_initialize_request() { }; let expected_req = JSONRPCRequest { + jsonrpc: JSONRPC_VERSION.into(), id: RequestId::Integer(1), method: "initialize".into(), params: Some(json!({