context_servers: Fix tool/list and prompt/list (#20387)

David Soria Parra created

There are two issues with too/list and prompt/list at the moment. We
serialize params to `null`, which is not correct according to
context_server spec. While it IS allowed by JSON RPC spec to omit
params, it turns out some servers currently missbehave and don't respect
this. So we do two things

- We omit params if it would be a null value in json.
- We explicitly set params to {} for tool/list and prompt/list to avoid
it being omitted.

Release Notes:

- N/A

Change summary

crates/context_servers/src/client.rs   |  9 +++++++++
crates/context_servers/src/protocol.rs | 10 ++++++++--
2 files changed, 17 insertions(+), 2 deletions(-)

Detailed changes

crates/context_servers/src/client.rs 🔗

@@ -55,11 +55,20 @@ pub struct Client {
 #[repr(transparent)]
 pub struct ContextServerId(pub String);
 
+fn is_null_value<T: Serialize>(value: &T) -> bool {
+    if let Ok(Value::Null) = serde_json::to_value(value) {
+        true
+    } else {
+        false
+    }
+}
+
 #[derive(Serialize, Deserialize)]
 struct Request<'a, T> {
     jsonrpc: &'static str,
     id: RequestId,
     method: &'a str,
+    #[serde(skip_serializing_if = "is_null_value")]
     params: T,
 }
 

crates/context_servers/src/protocol.rs 🔗

@@ -113,7 +113,10 @@ impl InitializedContextServerProtocol {
 
         let response: types::PromptsListResponse = self
             .inner
-            .request(types::RequestType::PromptsList.as_str(), ())
+            .request(
+                types::RequestType::PromptsList.as_str(),
+                serde_json::json!({}),
+            )
             .await?;
 
         Ok(response.prompts)
@@ -125,7 +128,10 @@ impl InitializedContextServerProtocol {
 
         let response: types::ResourcesListResponse = self
             .inner
-            .request(types::RequestType::ResourcesList.as_str(), ())
+            .request(
+                types::RequestType::ResourcesList.as_str(),
+                serde_json::json!({}),
+            )
             .await?;
 
         Ok(response)