fix: stamp server info on graceful subscription results (#1078)
* fix: stamp server info on graceful subscription results * fix: expose subscription server info metadata --------- Co-authored-by: mrcs64 <9069178+mrcs64@users.noreply.github.com>
This commit is contained in:
parent
4e361b715f
commit
cb50ae7890
5 changed files with 94 additions and 26 deletions
|
|
@ -3450,6 +3450,14 @@
|
|||
"SubscriptionsListenResultMeta": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"io.modelcontextprotocol/serverInfo": {
|
||||
"description": "Identifies the server software producing the response. Servers SHOULD include this field on every response unless specifically configured not to do so.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Implementation"
|
||||
}
|
||||
]
|
||||
},
|
||||
"io.modelcontextprotocol/subscriptionId": {
|
||||
"$ref": "#/definitions/NumberOrString"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3450,6 +3450,14 @@
|
|||
"SubscriptionsListenResultMeta": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"io.modelcontextprotocol/serverInfo": {
|
||||
"description": "Identifies the server software producing the response. Servers SHOULD include this field on every response unless specifically configured not to do so.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Implementation"
|
||||
}
|
||||
]
|
||||
},
|
||||
"io.modelcontextprotocol/subscriptionId": {
|
||||
"$ref": "#/definitions/NumberOrString"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ impl ServerHandler for ToolsOnlyServer {
|
|||
.enable_tool_list_changed()
|
||||
.build(),
|
||||
)
|
||||
.with_server_info(Implementation::new("tools-only-server", "1.0.0"))
|
||||
}
|
||||
|
||||
fn accepted_subscription_filter(
|
||||
|
|
@ -440,6 +441,13 @@ async fn listen_exposes_acknowledged_filter_and_graceful_result() -> anyhow::Res
|
|||
result.meta.subscription_id().as_ref(),
|
||||
Some(subscription.id())
|
||||
);
|
||||
assert_eq!(
|
||||
result
|
||||
.meta
|
||||
.server_info()
|
||||
.expect("graceful result should contain valid server info"),
|
||||
Implementation::new("tools-only-server", "1.0.0")
|
||||
);
|
||||
|
||||
client.cancel().await?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rmcp::model::{
|
||||
ClientJsonRpcMessage, ClientRequest, GetMeta, JsonRpcNotification, JsonRpcRequest,
|
||||
NotificationMetaObject, RequestId, RequestMetaObject, ServerJsonRpcMessage, ServerNotification,
|
||||
SubscriptionFilter, SubscriptionsAcknowledgedNotification,
|
||||
ClientJsonRpcMessage, ClientRequest, GetMeta, Implementation, JsonRpcNotification,
|
||||
JsonRpcRequest, NotificationMetaObject, RequestId, RequestMetaObject, ServerJsonRpcMessage,
|
||||
ServerNotification, SubscriptionFilter, SubscriptionsAcknowledgedNotification,
|
||||
SubscriptionsAcknowledgedNotificationParams, SubscriptionsListenRequest,
|
||||
SubscriptionsListenRequestParams, SubscriptionsListenResult, SubscriptionsListenResultMeta,
|
||||
};
|
||||
|
|
@ -155,6 +155,7 @@ fn acknowledged_notification_round_trips_numeric_subscription_id_and_metadata()
|
|||
#[test]
|
||||
fn listen_result_requires_matching_string_subscription_id_and_preserves_metadata() {
|
||||
let mut meta = SubscriptionsListenResultMeta::new(RequestId::String("subscription-2".into()));
|
||||
meta.set_server_info(Implementation::new("test-server", "1.0.0"));
|
||||
meta.insert("com.example/result".into(), json!({ "reason": "shutdown" }));
|
||||
let result = SubscriptionsListenResult::new(meta);
|
||||
|
||||
|
|
@ -165,6 +166,10 @@ fn listen_result_requires_matching_string_subscription_id_and_preserves_metadata
|
|||
"resultType": "complete",
|
||||
"_meta": {
|
||||
"io.modelcontextprotocol/subscriptionId": "subscription-2",
|
||||
"io.modelcontextprotocol/serverInfo": {
|
||||
"name": "test-server",
|
||||
"version": "1.0.0",
|
||||
},
|
||||
"com.example/result": {
|
||||
"reason": "shutdown",
|
||||
},
|
||||
|
|
@ -178,6 +183,10 @@ fn listen_result_requires_matching_string_subscription_id_and_preserves_metadata
|
|||
round_trip.meta.subscription_id(),
|
||||
Some(RequestId::String("subscription-2".into()))
|
||||
);
|
||||
assert_eq!(
|
||||
round_trip.meta.server_info(),
|
||||
Some(Implementation::new("test-server", "1.0.0"))
|
||||
);
|
||||
assert_eq!(
|
||||
round_trip.meta.get("com.example/result"),
|
||||
Some(&json!({ "reason": "shutdown" }))
|
||||
|
|
@ -232,5 +241,14 @@ fn subscription_schemas_mark_only_draft_required_fields_as_required() {
|
|||
acknowledgment_schema["properties"]["_meta"]["$ref"],
|
||||
"#/$defs/NotificationMetaObject"
|
||||
);
|
||||
let result_meta_schema = &result_schema["$defs"]["SubscriptionsListenResultMeta"];
|
||||
assert_eq!(
|
||||
result_meta_schema["properties"]["io.modelcontextprotocol/serverInfo"]["allOf"][0]["$ref"],
|
||||
"#/$defs/Implementation"
|
||||
);
|
||||
assert_eq!(
|
||||
result_meta_schema["required"],
|
||||
json!(["io.modelcontextprotocol/subscriptionId"])
|
||||
);
|
||||
assert_eq!(result_schema["required"], json!(["resultType", "_meta"]));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ use std::{
|
|||
use rmcp::{
|
||||
ClientLifecycleMode, ClientServiceExt, ServerHandler,
|
||||
model::{
|
||||
ClientInfo, ClientRequest, ListToolsRequest, ProtocolVersion, RequestMetaObject,
|
||||
ServerCapabilities, ServerInfo, ServerNotification, SubscriptionFilter,
|
||||
ClientInfo, ClientRequest, Implementation, ListToolsRequest, ProtocolVersion,
|
||||
RequestMetaObject, ServerCapabilities, ServerInfo, ServerNotification, SubscriptionFilter,
|
||||
},
|
||||
service::{PeerRequestOptions, SubscriptionContext, SubscriptionEnd},
|
||||
transport::{
|
||||
|
|
@ -59,6 +59,7 @@ impl ServerHandler for HttpSubscriptionServer {
|
|||
.enable_tool_list_changed()
|
||||
.build(),
|
||||
)
|
||||
.with_server_info(Implementation::new("http-subscription-server", "1.0.0"))
|
||||
}
|
||||
|
||||
fn accepted_subscription_filter(
|
||||
|
|
@ -217,10 +218,16 @@ async fn modern_http_graceful_close_returns_final_listen_result() -> anyhow::Res
|
|||
|
||||
assert!(subscription.next().await?.is_some());
|
||||
assert!(subscription.next().await?.is_none());
|
||||
assert!(matches!(
|
||||
subscription.end(),
|
||||
Some(SubscriptionEnd::Graceful(_))
|
||||
));
|
||||
let Some(SubscriptionEnd::Graceful(result)) = subscription.end() else {
|
||||
panic!("expected graceful final result");
|
||||
};
|
||||
assert_eq!(
|
||||
result
|
||||
.meta
|
||||
.server_info()
|
||||
.expect("graceful result should contain valid server info"),
|
||||
Implementation::new("http-subscription-server", "1.0.0")
|
||||
);
|
||||
|
||||
client.cancel().await?;
|
||||
server_ct.cancel();
|
||||
|
|
|
|||
Loading…
Reference in a new issue