[app-server-protocol] introduce generic ServerResponse for app-server-protocol (#17044)

- introduces `ServerResponse` as the symmetrical typed response union to
`ServerRequest` for app-server-protocol
- enables scalable event stream ingestion for use cases such as
analytics, particularly for tools/approvals
- no runtime behavior changes, protocol/schema plumbing only
- mirrors #15921
This commit is contained in:
rhan-oai
2026-04-07 14:50:27 -07:00
committed by GitHub
parent e9702411ab
commit f480b98984

View File

@@ -620,6 +620,41 @@ macro_rules! server_request_definitions {
}
}
/// Typed response from the client to the server.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "method", rename_all = "camelCase")]
pub enum ServerResponse {
$(
$(#[$variant_meta])*
$(#[serde(rename = $wire)])?
$variant {
#[serde(rename = "id")]
request_id: RequestId,
response: $response,
},
)*
}
impl ServerResponse {
pub fn id(&self) -> &RequestId {
match self {
$(Self::$variant { request_id, .. } => request_id,)*
}
}
pub fn method(&self) -> String {
serde_json::to_value(self)
.ok()
.and_then(|value| {
value
.get("method")
.and_then(serde_json::Value::as_str)
.map(str::to_owned)
})
.unwrap_or_else(|| "<unknown>".to_string())
}
}
#[derive(Debug, Clone, PartialEq, JsonSchema)]
#[allow(clippy::large_enum_variant)]
pub enum ServerRequestPayload {
@@ -1230,6 +1265,30 @@ mod tests {
Ok(())
}
#[test]
fn serialize_server_response() -> Result<()> {
let response = ServerResponse::CommandExecutionRequestApproval {
request_id: RequestId::Integer(8),
response: v2::CommandExecutionRequestApprovalResponse {
decision: v2::CommandExecutionApprovalDecision::AcceptForSession,
},
};
assert_eq!(response.id(), &RequestId::Integer(8));
assert_eq!(response.method(), "item/commandExecution/requestApproval");
assert_eq!(
json!({
"method": "item/commandExecution/requestApproval",
"id": 8,
"response": {
"decision": "acceptForSession"
}
}),
serde_json::to_value(&response)?,
);
Ok(())
}
#[test]
fn serialize_mcp_server_elicitation_request() -> Result<()> {
let requested_schema: v2::McpElicitationSchema = serde_json::from_value(json!({